Thread (20 messages) flat view 20 messages, 2 authors, 2023-04-04

Re: [PATCH 01/10] locking/atomic: Add missing cast to try_cmpxchg() fallbacks

From: Uros Bizjak <hidden>
Date: 2023-04-04 12:25:47
Also in: linux-alpha, linux-arch, linux-mips, linux-perf-users, lkml, loongarch

On Mon, Apr 3, 2023 at 12:19 PM Mark Rutland [off-list ref] wrote:
On Sun, Mar 26, 2023 at 09:28:38PM +0200, Uros Bizjak wrote:
quoted
On Fri, Mar 24, 2023 at 5:33 PM Mark Rutland [off-list ref] wrote:
quoted
On Fri, Mar 24, 2023 at 04:14:22PM +0000, Mark Rutland wrote:
quoted
On Fri, Mar 24, 2023 at 04:43:32PM +0100, Uros Bizjak wrote:
quoted
On Fri, Mar 24, 2023 at 3:13 PM Mark Rutland [off-list ref] wrote:
quoted
On Sun, Mar 05, 2023 at 09:56:19PM +0100, Uros Bizjak wrote:
quoted
Cast _oldp to the type of _ptr to avoid incompatible-pointer-types warning.
Can you give an example of where we are passing an incompatible pointer?
An example is patch 10/10 from the series, which will fail without
this fix when fallback code is used. We have:

-       } while (local_cmpxchg(&rb->head, offset, head) != offset);
+       } while (!local_try_cmpxchg(&rb->head, &offset, head));

where rb->head is defined as:

typedef struct {
   atomic_long_t a;
} local_t;

while offset is defined as 'unsigned long'.
Ok, but that's because we're doing the wrong thing to start with.

Since local_t is defined in terms of atomic_long_t, we should define the
generic local_try_cmpxchg() in terms of atomic_long_try_cmpxchg(). We'll still
have a mismatch between 'long *' and 'unsigned long *', but then we can fix
that in the callsite:

      while (!local_try_cmpxchg(&rb->head, &(long *)offset, head))
Sorry, that should be:

        while (!local_try_cmpxchg(&rb->head, (long *)&offset, head))
The fallbacks are a bit more complicated than above, and are different
from atomic_try_cmpxchg.

Please note in patch 2/10, the falbacks when arch_try_cmpxchg_local
are not defined call arch_cmpxchg_local. Also in patch 2/10,
try_cmpxchg_local is introduced, where it calls
arch_try_cmpxchg_local. Targets (and generic code) simply define (e.g.
:

#define local_cmpxchg(l, o, n) \
       (cmpxchg_local(&((l)->a.counter), (o), (n)))
+#define local_try_cmpxchg(l, po, n) \
+       (try_cmpxchg_local(&((l)->a.counter), (po), (n)))

which is part of the local_t API. Targets should either define all
these #defines, or none. There are no partial fallbacks as is the case
with atomic_t.
Whether or not there are fallbacks is immaterial.

In those cases, architectures can just as easily write C wrappers, e.g.

long local_cmpxchg(local_t *l, long old, long new)
{
        return cmpxchg_local(&l->a.counter, old, new);
}

long local_try_cmpxchg(local_t *l, long *old, long new)
{
        return try_cmpxchg_local(&l->a.counter, old, new);
}
Please find attached the complete prototype patch that implements the
above suggestion.

The patch includes:
- implementation of instrumented try_cmpxchg{,64}_local definitions
- corresponding arch_try_cmpxchg{,64}_local fallback definitions
- generic local{,64}_try_cmpxchg (and local{,64}_cmpxchg) C wrappers

- x86 specific local_try_cmpxchg (and local_cmpxchg) C wrappers
- x86 specific arch_try_cmpxchg_local definition

- kernel/events/ring_buffer.c change to test local_try_cmpxchg
implementation and illustrate the transition
- arch/x86/events/core.c change to test local64_try_cmpxchg
implementation and illustrate the transition

The definition of atomic_long_t is different for 64-bit and 32-bit
targets (s64 vs int), so target specific C wrappers have to use
different casts to account for this difference.

Uros.

Attachments

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help