From: Will Deacon <will.deacon@arm.com>
To: ksummit-discuss@lists.linuxfoundation.org
Cc: peterz@infradead.org, waiman.long@hp.com
Subject: [Ksummit-discuss] [TECH TOPIC] asm-generic implementations of low-level synchronisation constructs
Date: Wed, 7 May 2014 19:29:16 +0100 [thread overview]
Message-ID: <20140507182916.GG3694@arm.com> (raw)
Hi all,
Traditionally, low-level synchronisation and atomic constructs have been
buried away in arch-specific code, with new arch maintainers having to
wrestle with Documentation/{memory-barriers,atomic_ops}.txt to ensure
they provide the (somewhat arbitrary) semantics expected by the kernel.
However, over the past year, there have been some notable events in this
area:
(1) The addition of smp_load_acquire/smp_store_release across all
architectures (including asm-generic)
https://lwn.net/Articles/576486/
(2) Merging of generic MCS spinlocks into kernel/locking, built using
the macros introduced by (1). There are other similar patches for
queued spinlocks and rwlocks, but they're not completely generic
afaict.
http://lwn.net/Articles/590243/
(3) C11 atomics seem to be more prominent on people's radar.
http://lwn.net/Articles/586838/
In light of these developments, I'd like to revisit what we expect from
architectures in the way of atomics and locks. Ultimately, this means
trying to construct efficient (not just functional!) spinlock, rwlock,
futex and bitop implementations in asm-generic which would be build out
of suitable, simple(r) atomic operations implemented by each architecture.
For example, a dumb spinlock can be constructed with our [cmp]xchg:
dumb_spin_lock(atomic_t *lock)
{
while (atomic_cmpxchg(lock, 0, 1))
cpu_relax();
}
dumb_spin_unlock(atomic_t *lock)
{
atomic_xchg(lock, 0);
}
but nobody is going to flock to such an implementation. It's unfair and
has additional barrier overhead on weakly-ordered architectures.
What we'd like to write is something like (just trying to show the atomics
-- this is likely not endian-clean at least):
#define TICKET_SHIFT 16
#define TICKET_MASK ((1 << TICKET_SHIFT) - 1)
better_spin_lock(atomic_t *lock)
{
/*
* Atomic add to lock with acquire semantics, returning original
* value.
*/
int old = atomic_xchg_add(ACQUIRE, lock, 1 << TICKET_SHIFT);
if ((old << TICKET_SHIFT) == (old & (TICKET_MASK << TICKET_SHIFT)))
return; /* Got the lock */
while (smp_load_acquire((u16 *)lock) != (old >> TICKET_SHIFT))
cpu_relax();
}
better_spin_unlock(atomic_t *lock)
{
smp_store_release((u16 *)lock, atomic_read(lock) + 1);
}
which isn't perfect, but is much better than before and made possible by
the addition of atomic_xchg_add. The remaining parts to address are things
like power saving when spinning and synchronising unlock with I/O accesses,
but they will likely remain arch-specific. We should be able to do a similar
thing for other locking constructs.
Increasing the number of atomic operations would also help us to define
a cleaner interface to them, potentially easing any adoption of C11 atomics
in future. For example, rather than saying "atomic_set() does not imply
barriers" and "atomic_xchg() requires explicit memory barriers around the
operation", we could have store/release/store+release variants of them both
(similar to C11 and OpenCL). As it stands, there are a couple of cases
where atomic_xchg is used in preference to atomic_set + appropriate barriers
(just look for uses of xchg where the return value is ignored).
Another related area to clean up is the semantics around conditional
atomics (cmpxchg, add_unless, dec_if_positive etc) and barriers on the
failure paths.
Anyway, I've proposed this as a [TECH TOPIC] because I think sitting down
for half a day with other people interested in this problem could result
in us deciding on an initial set of atomic operations from which to build
efficient, generic locking constructs. That later part can definitely
happen on LKML, but the first steps will be a lot easier face-to-face.
Key people for this would be:
- Peter Zijlstra
- Ben Herrenschmidt
- Paul McKenney
- Waiman Long
- Arnd Bergmann
Cheers,
Will
next reply other threads:[~2014-05-07 18:29 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-05-07 18:29 Will Deacon [this message]
2014-05-07 19:12 ` Peter Zijlstra
2014-05-07 21:20 ` Will Deacon
2014-05-08 9:13 ` Peter Zijlstra
2014-05-08 14:27 ` Peter Zijlstra
2014-05-08 14:43 ` David Woodhouse
2014-05-08 15:13 ` Will Deacon
2014-05-08 16:39 ` Paul E. McKenney
2014-05-07 21:17 ` Waiman Long
2014-05-07 21:26 ` Peter Zijlstra
2014-05-07 22:29 ` Waiman Long
2014-05-08 14:16 ` Will Deacon
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=20140507182916.GG3694@arm.com \
--to=will.deacon@arm.com \
--cc=ksummit-discuss@lists.linuxfoundation.org \
--cc=peterz@infradead.org \
--cc=waiman.long@hp.com \
/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