linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Andrew Morton <andrewm@uow.edu.au>
To: lkml <linux-kernel@vger.kernel.org>
Subject: [patch] semaphore optimisation
Date: Sat, 18 Nov 2000 14:53:50 +1100	[thread overview]
Message-ID: <3A15FD4E.B11875BE@uow.edu.au> (raw)


This patch modestly improves the scalability and straight-line
performance of x86 semaphores by removing the semaphore_lock and using
the per-semaphore lock instead.  If removes several spinlock operations
and allows concurrent operations on separate semaphores.

No bugs were harmed in the preparation of this patch.  It's just me
fartarsing aound.




--- linux-2.4.0-test11-pre7/include/linux/sched.h	Sat Nov 18 13:55:32 2000
+++ linux-akpm/include/linux/sched.h	Sat Nov 18 14:42:26 2000
@@ -535,6 +535,7 @@
 #define CURRENT_TIME (xtime.tv_sec)
 
 extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode, unsigned int wq_mode));
+extern void FASTCALL(____wake_up(wait_queue_head_t *q, unsigned int mode, unsigned int wq_mode));
 extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, unsigned int wq_mode));
 extern void FASTCALL(sleep_on(wait_queue_head_t *q));
 extern long FASTCALL(sleep_on_timeout(wait_queue_head_t *q,
--- linux-2.4.0-test11-pre7/include/linux/wait.h	Sat Nov 18 13:55:32 2000
+++ linux-akpm/include/linux/wait.h	Sat Nov 18 14:42:26 2000
@@ -72,6 +72,7 @@
 # define wq_read_unlock_irqrestore read_unlock_irqrestore
 # define wq_read_unlock read_unlock
 # define wq_write_lock_irq write_lock_irq
+# define wq_write_unlock_irq write_unlock_irq
 # define wq_write_lock_irqsave write_lock_irqsave
 # define wq_write_unlock_irqrestore write_unlock_irqrestore
 # define wq_write_unlock write_unlock
@@ -84,6 +85,7 @@
 # define wq_read_unlock spin_unlock
 # define wq_read_unlock_irqrestore spin_unlock_irqrestore
 # define wq_write_lock_irq spin_lock_irq
+# define wq_write_unlock_irq spin_unlock_irq
 # define wq_write_lock_irqsave spin_lock_irqsave
 # define wq_write_unlock_irqrestore spin_unlock_irqrestore
 # define wq_write_unlock spin_unlock
--- linux-2.4.0-test11-pre7/arch/i386/kernel/semaphore.c	Sat Nov 18 13:55:28 2000
+++ linux-akpm/arch/i386/kernel/semaphore.c	Sat Nov 18 14:42:26 2000
@@ -53,16 +53,15 @@
 	wake_up(&sem->wait);
 }
 
-static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED;
-
 void __down(struct semaphore * sem)
 {
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
-	tsk->state = TASK_UNINTERRUPTIBLE;
-	add_wait_queue_exclusive(&sem->wait, &wait);
 
-	spin_lock_irq(&semaphore_lock);
+	tsk->state = TASK_UNINTERRUPTIBLE;
+	wq_write_lock_irq(&sem->wait.lock);
+	wait.flags = WQ_FLAG_EXCLUSIVE;
+	__add_wait_queue_tail(&sem->wait, &wait);
 	sem->sleepers++;
 	for (;;) {
 		int sleepers = sem->sleepers;
@@ -76,14 +75,14 @@
 			break;
 		}
 		sem->sleepers = 1;	/* us - see -1 above */
-		spin_unlock_irq(&semaphore_lock);
+		wq_write_unlock_irq(&sem->wait.lock);
 
 		schedule();
 		tsk->state = TASK_UNINTERRUPTIBLE;
-		spin_lock_irq(&semaphore_lock);
+		wq_write_lock_irq(&sem->wait.lock);
 	}
-	spin_unlock_irq(&semaphore_lock);
-	remove_wait_queue(&sem->wait, &wait);
+	__remove_wait_queue(&sem->wait, &wait);
+	wq_write_unlock_irq(&sem->wait.lock);
 	tsk->state = TASK_RUNNING;
 	wake_up(&sem->wait);
 }
@@ -93,10 +92,11 @@
 	int retval = 0;
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
-	tsk->state = TASK_INTERRUPTIBLE;
-	add_wait_queue_exclusive(&sem->wait, &wait);
 
-	spin_lock_irq(&semaphore_lock);
+	tsk->state = TASK_INTERRUPTIBLE;
+	wq_write_lock_irq(&sem->wait.lock);
+	wait.flags = WQ_FLAG_EXCLUSIVE;
+	__add_wait_queue_tail(&sem->wait, &wait);
 	sem->sleepers ++;
 	for (;;) {
 		int sleepers = sem->sleepers;
@@ -126,15 +126,15 @@
 			break;
 		}
 		sem->sleepers = 1;	/* us - see -1 above */
-		spin_unlock_irq(&semaphore_lock);
+		wq_write_unlock_irq(&sem->wait.lock);
 
 		schedule();
 		tsk->state = TASK_INTERRUPTIBLE;
-		spin_lock_irq(&semaphore_lock);
+		wq_write_lock_irq(&sem->wait.lock);
 	}
-	spin_unlock_irq(&semaphore_lock);
+	__remove_wait_queue(&sem->wait, &wait);
+	wq_write_unlock_irq(&sem->wait.lock);
 	tsk->state = TASK_RUNNING;
-	remove_wait_queue(&sem->wait, &wait);
 	wake_up(&sem->wait);
 	return retval;
 }
@@ -152,7 +152,7 @@
 	int sleepers;
 	unsigned long flags;
 
-	spin_lock_irqsave(&semaphore_lock, flags);
+	wq_write_lock_irqsave(&sem->wait.lock, flags);
 	sleepers = sem->sleepers + 1;
 	sem->sleepers = 0;
 
@@ -161,9 +161,9 @@
 	 * playing, because we own the spinlock.
 	 */
 	if (!atomic_add_negative(sleepers, &sem->count))
-		wake_up(&sem->wait);
+		____wake_up(&sem->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, WQ_FLAG_EXCLUSIVE);
 
-	spin_unlock_irqrestore(&semaphore_lock, flags);
+	wq_write_unlock_irqrestore(&sem->wait.lock, flags);
 	return 1;
 }
 
--- linux-2.4.0-test11-pre7/kernel/sched.c	Sat Nov 18 13:55:32 2000
+++ linux-akpm/kernel/sched.c	Sat Nov 18 14:42:26 2000
@@ -700,7 +700,7 @@
 }
 
 static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode,
-				     unsigned int wq_mode, const int sync)
+				     unsigned int wq_mode, const int sync, const int do_locking)
 {
 	struct list_head *tmp, *head;
 	struct task_struct *p, *best_exclusive;
@@ -713,7 +713,8 @@
 	best_cpu = smp_processor_id();
 	irq = in_interrupt();
 	best_exclusive = NULL;
-	wq_write_lock_irqsave(&q->lock, flags);
+	if (do_locking)
+		wq_write_lock_irqsave(&q->lock, flags);
 
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC_WQHEAD(q);
@@ -768,19 +769,25 @@
 		else
 			wake_up_process(best_exclusive);
 	}
-	wq_write_unlock_irqrestore(&q->lock, flags);
+	if (do_locking)
+		wq_write_unlock_irqrestore(&q->lock, flags);
 out:
 	return;
 }
 
 void __wake_up(wait_queue_head_t *q, unsigned int mode, unsigned int wq_mode)
 {
-	__wake_up_common(q, mode, wq_mode, 0);
+	__wake_up_common(q, mode, wq_mode, 0, 1);
+}
+
+void ____wake_up(wait_queue_head_t *q, unsigned int mode, unsigned int wq_mode)
+{
+	__wake_up_common(q, mode, wq_mode, 0, 0);
 }
 
 void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, unsigned int wq_mode)
 {
-	__wake_up_common(q, mode, wq_mode, 1);
+	__wake_up_common(q, mode, wq_mode, 1, 1);
 }
 
 #define	SLEEP_ON_VAR				\
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/

                 reply	other threads:[~2000-11-18  4:24 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=3A15FD4E.B11875BE@uow.edu.au \
    --to=andrewm@uow.edu.au \
    --cc=linux-kernel@vger.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).