Messages in this thread | | | Date | Fri, 25 Feb 2011 13:25:57 -0500 | From | Mathieu Desnoyers <> | Subject | Re: [cpuops cmpxchg double V3 3/5] Generic support for this_cpu_cmpxchg_double |
| |
* Christoph Lameter (cl@linux.com) wrote: > Introduce this_cpu_cmpxchg_double. this_cpu_cmpxchg_double() allows the > comparision between two consecutive words and replaces them if there is
comparison
/nitpick again ;)
Mathieu
> a match. > > bool this_cpu_cmpxchg_double(pcp1, pcp2, > old_word1, old_word2, new_word1, new_word2) > > this_cpu_cmpxchg_double does not return the old value (difficult since > there are two words) but a boolean indicating if the operation was > successful. > > The first percpu variable must be double word aligned! > > Signed-off-by: Christoph Lameter <cl@linux.com> > > --- > include/linux/percpu.h | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 130 insertions(+) > > Index: linux-2.6/include/linux/percpu.h > =================================================================== > --- linux-2.6.orig/include/linux/percpu.h 2011-01-10 10:22:35.000000000 -0600 > +++ linux-2.6/include/linux/percpu.h 2011-01-10 10:26:43.000000000 -0600 > @@ -255,6 +255,29 @@ extern void __bad_size_call_parameter(vo > pscr2_ret__; \ > }) > > +/* > + * Special handling for cmpxchg_double. cmpxchg_double is passed two > + * percpu variables. The first has to be aligned to a double word > + * boundary and the second has to follow directly thereafter. > + */ > +#define __pcpu_double_call_return_int(stem, pcp1, pcp2, ...) \ > +({ \ > + int ret__; \ > + __verify_pcpu_ptr(&pcp1); \ > + VM_BUG_ON((unsigned long)(&pcp1) % (2 * sizeof(pcp1))); \ > + VM_BUG_ON((unsigned long)(&pcp2) != (unsigned long)(&pcp1) + sizeof(pcp1));\ > + VM_BUG_ON(sizeof(pcp1) != sizeof(pcp2)); \ > + switch(sizeof(pcp1)) { \ > + case 1: ret__ = stem##1(pcp1, pcp2, __VA_ARGS__);break; \ > + case 2: ret__ = stem##2(pcp1, pcp2, __VA_ARGS__);break; \ > + case 4: ret__ = stem##4(pcp1, pcp2, __VA_ARGS__);break; \ > + case 8: ret__ = stem##8(pcp1, pcp2, __VA_ARGS__);break; \ > + default: \ > + __bad_size_call_parameter();break; \ > + } \ > + ret__; \ > +}) > + > #define __pcpu_size_call(stem, variable, ...) \ > do { \ > __verify_pcpu_ptr(&(variable)); \ > @@ -318,6 +341,80 @@ do { \ > # define this_cpu_read(pcp) __pcpu_size_call_return(this_cpu_read_, (pcp)) > #endif > > +/* > + * cmpxchg_double replaces two adjacent scalars at once. The first two > + * parameters are per cpu variables which have to be of the same size. > + * A truth value is returned to indicate success or > + * failure (since a double register result is difficult to handle). > + * There is very limited hardware support for these operations. So only certain > + * sizes may work. > + */ > +#define __this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > +({ \ > + int __ret = 0; \ > + if (__this_cpu_read(pcp1) == (oval1) && \ > + __this_cpu_read(pcp2) == (oval2)) { \ > + __this_cpu_write(pcp1, (nval1)); \ > + __this_cpu_write(pcp2, (nval2)); \ > + __ret = 1; \ > + } \ > + (__ret); \ > +}) > + > +#ifndef __this_cpu_cmpxchg_double > +# ifndef __this_cpu_cmpxchg_double_1 > +# define __this_cpu_cmpxchg_double_1(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + __this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) > +# endif > +# ifndef __this_cpu_cmpxchg_double_2 > +# define __this_cpu_cmpxchg_double_2(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + __this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) > +# endif > +# ifndef __this_cpu_cmpxchg_double_4 > +# define __this_cpu_cmpxchg_double_4(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + __this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) > +# endif > +# ifndef __this_cpu_cmpxchg_double_8 > +# define __this_cpu_cmpxchg_double_8(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + __this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) > +# endif > +# define __this_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + __pcpu_double_call_return_int(__this_cpu_cmpxchg_double_, (pcp1), (pcp2) \ > + oval1, oval2, nval1, nval2) > +#endif > + > +#define _this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > +({ \ > + int ret__; \ > + preempt_disable(); \ > + ret__ = __this_cpu_generic_cmpxchg_double(pcp1, pcp2, \ > + oval1, oval2, nval1, nval2); \ > + preempt_enable(); \ > + ret__; \ > +}) > + > +#ifndef this_cpu_cmpxchg_double > +# ifndef this_cpu_cmpxchg_double_1 > +# define this_cpu_cmpxchg_double_1(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + _this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) > +# endif > +# ifndef this_cpu_cmpxchg_double_2 > +# define this_cpu_cmpxchg_double_2(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + _this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) > +# endif > +# ifndef this_cpu_cmpxchg_double_4 > +# define this_cpu_cmpxchg_double_4(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + _this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) > +# endif > +# ifndef this_cpu_cmpxchg_double_8 > +# define this_cpu_cmpxchg_double_8(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + _this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) > +# endif > +# define this_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + __pcpu_double_call_return_int(this_cpu_cmpxchg_double_, (pcp1), (pcp2), \ > + oval1, oval2, nval1, nval2) > +#endif > + > #define _this_cpu_generic_to_op(pcp, val, op) \ > do { \ > preempt_disable(); \ > @@ -823,4 +920,37 @@ do { \ > __pcpu_size_call_return2(irqsafe_cpu_cmpxchg_, (pcp), oval, nval) > #endif > > +#define irqsafe_generic_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > +({ \ > + int ret__; \ > + unsigned long flags; \ > + local_irq_save(flags); \ > + ret__ = __this_cpu_generic_cmpxchg_double(pcp1, pcp2, \ > + oval1, oval2, nval1, nval2); \ > + local_irq_restore(flags); \ > + ret__; \ > +}) > + > +#ifndef irqsafe_cpu_cmpxchg_double > +# ifndef irqsafe_cpu_cmpxchg_double_1 > +# define irqsafe_cpu_cmpxchg_double_1(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + irqsafe_generic_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) > +# endif > +# ifndef irqsafe_cpu_cmpxchg_double_2 > +# define irqsafe_cpu_cmpxchg_double_2(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + irqsafe_generic_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) > +# endif > +# ifndef irqsafe_cpu_cmpxchg_double_4 > +# define irqsafe_cpu_cmpxchg_double_4(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + irqsafe_generic_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) > +# endif > +# ifndef irqsafe_cpu_cmpxchg_double_8 > +# define irqsafe_cpu_cmpxchg_double_8(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + irqsafe_generic_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) > +# endif > +# define irqsafe_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ > + __pcpu_double_call_return_int(irqsafe_cpu_cmpxchg_double_, (pcp1), (pcp2), \ > + oval1, oval2, nval1, nval2) > +#endif > + > #endif /* __LINUX_PERCPU_H */ >
-- Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
| |