From: Tim Chen <tim.c.chen@linux.intel.com>
To: Waiman Long <Waiman.Long@hp.com>
Cc: Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>, "H. Peter Anvin" <hpa@zytor.com>,
Arnd Bergmann <arnd@arndb.de>,
linux-arch@vger.kernel.org, x86@kernel.org,
linux-kernel@vger.kernel.org,
Peter Zijlstra <peterz@infradead.org>,
Steven Rostedt <rostedt@goodmis.org>,
Andrew Morton <akpm@linux-foundation.org>,
Michel Lespinasse <walken@google.com>,
Andi Kleen <andi@firstfloor.org>, Rik van Riel <riel@redhat.com>,
"Paul E. McKenney" <paulmck@linux.vnet.ibm.com>,
Linus Torvalds <torvalds@linux-foundation.org>,
Raghavendra K T <raghavendra.kt@linux.vnet.ibm.com>,
George Spelvin <linux@horizon.com>,
Daniel J Blueman <daniel@numascale.com>,
Alexander Fyodorov <halcy@yandex.ru>,
Aswin Chandramouleeswaran <aswin@hp.com>,
Scott J Norton <scott.norton@hp.com>,
Thavatchai Makphaibulchoke <thavatchai.makpahibulchoke@hp.com>
Subject: Re: [PATCH v3 1/2] qspinlock: Introducing a 4-byte queue spinlock implementation
Date: Thu, 30 Jan 2014 11:00:30 -0800 [thread overview]
Message-ID: <1391108430.3138.86.camel@schen9-DESK> (raw)
In-Reply-To: <1390933151-1797-2-git-send-email-Waiman.Long@hp.com>
On Tue, 2014-01-28 at 13:19 -0500, Waiman Long wrote:
> +/**
> + * queue_spin_lock_slowpath - acquire the queue spinlock
> + * @lock: Pointer to queue spinlock structure
> + */
> +void queue_spin_lock_slowpath(struct qspinlock *lock)
> +{
> + unsigned int cpu_nr, qn_idx;
> + struct qnode *node, *next = NULL;
> + u32 prev_qcode, my_qcode;
> +
> + /*
> + * Get the queue node
> + */
> + cpu_nr = smp_processor_id();
> + node = this_cpu_ptr(&qnodes[0]);
> + qn_idx = 0;
> +
> + if (unlikely(node->used)) {
> + /*
> + * This node has been used, try to find an empty queue
> + * node entry.
> + */
> + for (qn_idx = 1; qn_idx < MAX_QNODES; qn_idx++)
> + if (!node[qn_idx].used)
> + break;
> + if (unlikely(qn_idx == MAX_QNODES)) {
> + /*
> + * This shouldn't happen, print a warning message
> + * & busy spinning on the lock.
> + */
> + printk_sched(
> + "qspinlock: queue node table exhausted at cpu %d!\n",
> + cpu_nr);
> + while (!unfair_trylock(lock))
> + arch_mutex_cpu_relax();
> + return;
> + }
> + /* Adjust node pointer */
> + node += qn_idx;
> + }
> +
> + /*
> + * Set up the new cpu code to be exchanged
> + */
> + my_qcode = SET_QCODE(cpu_nr, qn_idx);
> +
If we get interrupted here before we have a chance to set the used flag,
the interrupt handler could pick up the same qnode if it tries to
acquire queued spin lock. Then we could overwrite the qcode we have set
here.
Perhaps an exchange operation for the used flag to prevent this race
condition?
Tim
> + /*
> + * The lock may be available at this point, try again before waiting
> + * in a queue.
> + */
> + if (queue_spin_trylock(lock))
> + return;
> +
> + /*
> + * Initialize the queue node
> + */
> + init_node(node, lock, cpu_nr);
> +
> + /*
> + * Exchange current copy of the queue node code
> + */
> + prev_qcode = xchg(&lock->qlcode, my_qcode);
> + /*
> + * It is possible that we may accidentally steal the lock. If this is
> + * the case, we need to either release it if not the head of the queue
> + * or get the lock and be done with it.
> + */
> + if (unlikely(!(prev_qcode & _QSPINLOCK_LOCKED))) {
> + if (prev_qcode == 0) {
> + /*
> + * Got the lock since it is at the head of the queue
> + * Now try to atomically clear the queue code.
> + */
> + if (cmpxchg(&lock->qlcode, my_qcode, _QSPINLOCK_LOCKED)
> + == my_qcode)
> + goto release_node;
> + /*
> + * The cmpxchg fails only if one or more processes
> + * are added to the queue. In this case, we need to
> + * notify the next one to be the head of the queue.
> + */
> + goto notify_next;
> + }
> + /*
> + * Accidentally steal the lock, release the lock and
> + * let the queue head get it.
> + */
> + queue_spin_unlock(lock);
> + } else
> + prev_qcode &= ~_QSPINLOCK_LOCKED; /* Clear the lock bit */
> + my_qcode &= ~_QSPINLOCK_LOCKED;
> +
> + if (prev_qcode) {
> + /*
> + * Not at the queue head, get the address of the previous node
> + * and set up the "next" fields of the that node.
> + */
> + struct qnode *prev = xlate_qcode(prev_qcode);
> +
> + assert_prevnode(prev, lock, cpu_nr);
> + ACCESS_ONCE(prev->next) = node;
> + /*
> + * Wait until the waiting flag is off
> + */
> + while (smp_load_acquire(&node->wait))
> + arch_mutex_cpu_relax();
> + }
> +
> + /*
> + * At the head of the wait queue now
> + */
> + while (true) {
> + u32 qcode;
> +
> + if (unlikely(!next)) {
> + /*
> + * Try to get the next node address & clean up
> + * current node data structure now if the next node
> + * address had been set.
> + */
> + next = ACCESS_ONCE(node->next);
> + if (next) {
> + assert_nextnode(next, lock, cpu_nr);
> + cleanup_node(node, cpu_nr);
> + node = NULL;
> + }
> + }
> + qcode = ACCESS_ONCE(lock->qlcode);
> + if (qcode & _QSPINLOCK_LOCKED)
> + ; /* Lock not available yet */
> + else if (qcode != my_qcode) {
> + /*
> + * Just get the lock with other spinners waiting
> + * in the queue.
> + */
> + if (unfair_trylock(lock))
> + /* May still need to notify the next node */
> + goto notify_next;
> + } else {
> + /*
> + * Get the lock & clear the queue code simultaneously
> + */
> + if (cmpxchg(&lock->qlcode, my_qcode,
> + _QSPINLOCK_LOCKED) == my_qcode)
> + /* No need to notify next one */
> + goto release_node;
> + }
> + arch_mutex_cpu_relax();
> + }
> +
> +notify_next:
> + /*
> + * If the next pointer is not set, we need to wait and notify the
> + * next one in line to do busy spinning.
> + */
> + if (unlikely(!next)) {
> + /*
> + * Wait until the next one in queue set up the next field
> + */
> + while (!(next = ACCESS_ONCE(node->next)))
> + arch_mutex_cpu_relax();
> + assert_nextnode(next, lock, cpu_nr);
> + }
> + /*
> + * The next one in queue is now at the head
> + */
> + smp_store_release(&next->wait, false);
> +
> +release_node:
> + if (node)
> + cleanup_node(node, cpu_nr);
> +}
> +EXPORT_SYMBOL(queue_spin_lock_slowpath);
next prev parent reply other threads:[~2014-01-30 19:00 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-01-28 18:19 [PATCH v3 0/2] qspinlock: Introducing a 4-byte queue spinlock Waiman Long
2014-01-28 18:19 ` [PATCH v3 1/2] qspinlock: Introducing a 4-byte queue spinlock implementation Waiman Long
2014-01-28 18:19 ` Waiman Long
2014-01-29 0:20 ` Andi Kleen
2014-01-29 0:20 ` Andi Kleen
2014-01-29 2:57 ` George Spelvin
2014-01-29 17:57 ` Waiman Long
2014-01-29 17:57 ` Waiman Long
2014-01-30 17:43 ` Rik van Riel
2014-01-30 19:00 ` Tim Chen [this message]
2014-01-30 19:28 ` Peter Zijlstra
2014-01-30 22:27 ` Tim Chen
2014-01-31 18:26 ` Waiman Long
2014-01-31 18:26 ` Waiman Long
2014-01-31 19:14 ` George Spelvin
2014-01-31 19:28 ` Waiman Long
2014-01-31 19:45 ` Peter Zijlstra
2014-01-31 18:16 ` Waiman Long
2014-01-30 19:35 ` Peter Zijlstra
2014-01-31 18:28 ` Waiman Long
2014-01-31 15:08 ` Peter Zijlstra
2014-01-31 19:24 ` Waiman Long
2014-01-31 19:24 ` Waiman Long
2014-01-31 19:51 ` Peter Zijlstra
2014-02-03 11:40 ` Peter Zijlstra
2014-02-06 3:10 ` Waiman Long
2014-02-07 18:17 ` Paul E. McKenney
2014-02-03 8:51 ` Raghavendra K T
2014-01-28 18:19 ` [PATCH v3 2/2] qspinlock, x86: Enable x86-64 to use queue spinlock Waiman Long
2014-01-30 17:45 ` Rik van Riel
2014-01-30 8:55 ` [PATCH v3 0/2] qspinlock: Introducing a 4-byte " Raghavendra K T
2014-01-30 15:38 ` Waiman Long
2014-01-30 15:38 ` Waiman Long
2014-01-30 18:49 ` Raghavendra K T
2014-02-03 8:51 ` Raghavendra K T
2014-02-03 8:51 ` Raghavendra K T
2014-02-06 3:09 ` Waiman Long
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=1391108430.3138.86.camel@schen9-DESK \
--to=tim.c.chen@linux.intel.com \
--cc=Waiman.Long@hp.com \
--cc=akpm@linux-foundation.org \
--cc=andi@firstfloor.org \
--cc=arnd@arndb.de \
--cc=aswin@hp.com \
--cc=daniel@numascale.com \
--cc=halcy@yandex.ru \
--cc=hpa@zytor.com \
--cc=linux-arch@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@horizon.com \
--cc=mingo@redhat.com \
--cc=paulmck@linux.vnet.ibm.com \
--cc=peterz@infradead.org \
--cc=raghavendra.kt@linux.vnet.ibm.com \
--cc=riel@redhat.com \
--cc=rostedt@goodmis.org \
--cc=scott.norton@hp.com \
--cc=tglx@linutronix.de \
--cc=thavatchai.makpahibulchoke@hp.com \
--cc=torvalds@linux-foundation.org \
--cc=walken@google.com \
--cc=x86@kernel.org \
/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;
as well as URLs for NNTP newsgroup(s).