|
|
Message-ID: <alpine.LNX.2.20.13.1706181620430.21867@monopod.intra.ispras.ru>
Date: Sun, 18 Jun 2017 16:40:56 +0300 (MSK)
From: Alexander Monakov <amonakov@...ras.ru>
To: musl@...ts.openwall.com
cc: Jens Gustedt <jens.gustedt@...ia.fr>
Subject: Re: [PATCH] a new lock algorithm with lock value and CS counts
in the same atomic int
Some style suggestions below.
On Fri, 16 Jun 2017, Jens Gustedt wrote:
> --- a/src/thread/__lock.c
> +++ b/src/thread/__lock.c
> @@ -1,15 +1,55 @@
> #include "pthread_impl.h"
>
> +
> +// INT_MIN for the lock, +1 for the count of this thread in the
> +// critical section, has it that the difference between locked and
> +// unlocked is ??INT_MAX.
> +#if (INT_MIN+1) != -INT_MAX
> +#error we need -INT_MAX to be INT_MIN+1
> +#endif
I suggest dropping this and spelling 'INT_MIN + current' as 'current - 1 -
INT_MAX' below. (all you need is that INT_MIN <= -INT_MAX)
> +
> void __lock(volatile int *l)
> {
> - if (libc.threads_minus_1)
> - while (a_swap(l, 1)) __wait(l, l+1, 1, 1);
> + /* This test is mostly useless, now. Leaving it to the first CAS is
> + probably just as efficient. */
> + if (libc.threads_minus_1) {
I suggest 'if (!libc.threads_minus_1) return;' and unindenting the rest of the
function.
> + int current = 0;
> + /* A first spin lock acquisition loop, for the case of
> + no or medium congestion. */
> + for (unsigned i = 0; i < 10; ++i) {
> + /* This is purely speculative. */
This comment, also duplicated below, doesn't look helpful.
> + if (current < 0) current += INT_MAX;
> + // assertion: current >= 0
> + int val = a_cas(l, current, current - INT_MAX);
> + if (val == current) return;
> + current = val;
Might be nice to use a_spin here.
> + }
> + // Spinning failed, so mark ourselves as being inside the CS.
> + current = a_fetch_add(l, 1) + 1;
> + /* The main lock acquisition loop for heavy congestion. The only
> + change to the value performed inside that loop is a successful
> + lock via the CAS that acquires the lock. */
> + for (;;) {
> + /* We can only go into wait, if we know that somebody holds the
> + lock and will eventually wake us up, again. */
> + if (current < 0) {
> + __syscall(SYS_futex, l, FUTEX_WAIT|FUTEX_PRIVATE, current, 0) != -ENOSYS
> + || __syscall(SYS_futex, l, FUTEX_WAIT, current, 0);
It's probably better to put this into a new static inline function in
pthread_impl.h next to __wake (e.g. __futexwait) and use it here and in __wait.
> + /* This is purely speculative. */
> + current += INT_MAX;
> + }
> + /* assertion: current > 0, because the count
> + includes us already. */
> + int val = a_cas(l, current, INT_MIN + current);
> + if (val == current) return;
> + current = val;
> + }
> + }
> }
>
> void __unlock(volatile int *l)
> {
> - if (l[0]) {
> - a_store(l, 0);
> - if (l[1]) __wake(l, 1, 1);
> + if (a_fetch_add(l, INT_MAX) != -INT_MAX) {
> + __syscall(SYS_futex, l, FUTEX_WAKE|FUTEX_PRIVATE, 1);
This change lost FUTEX_PRIVATE fallback handling; I don't see any reason not to
continue using __wake here.
> --- a/src/thread/pthread_detach.c
> +++ b/src/thread/pthread_detach.c
> @@ -6,7 +6,7 @@ int __pthread_join(pthread_t, void **);
> static int __pthread_detach(pthread_t t)
> {
> /* Cannot detach a thread that's already exiting */
> - if (a_swap(t->exitlock, 1))
> + if (a_cas(t->exitlock, 0, -INT_MAX))
> return __pthread_join(t, 0);
> t->detached = 2;
> __unlock(t->exitlock);
A good way to catch this would be to introduce a struct for the lock (out of
scope of this patch, of course).
Alexander
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.