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 [EMAIL PROTECTED]
Please read the FAQ at http://www.tux.org/lkml/

Reply via email to