All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Howells <dhowells@redhat.com>
To: torvalds@transmeta.com, Christoph Hellwig <hch@lst.de>,
	dhowells@redhat.com, linux-kernel@vger.kernel.org
Subject: [PATCH] rwsem trylock and downgrade part II
Date: Mon, 29 Jul 2002 09:12:56 +0100	[thread overview]
Message-ID: <17496.1027930376@warthog.cambridge.redhat.com> (raw)
In-Reply-To: Message from Christoph Hellwig <hch@lst.de>  of "Sun, 28 Jul 2002 20:24:19 +0200." <20020728202419.A24944@lst.de>


Hi Linus, Christoph,

I'm not sure what happened, but I think I applied an old incomplete patch when
patching 2.5.28, one that was missing Christoph's rwsem-spinlock stuff and the
trylock stuff. The attached patch adds these back (as per Christoph's patch),
it also adds a missing export to lib/rwsem.c.

When compiled for PentiumIII SMP, I see:

	dhowells>nm vmlinux | grep rwsem
	c01c5dbd t .text.lock.rwsem
	c02995a0 ? __kstrtab_rwsem_down_read_failed
	c02995b7 ? __kstrtab_rwsem_down_write_failed
	c02995da ? __kstrtab_rwsem_downgrade_wake
	c02995cf ? __kstrtab_rwsem_wake
	c02a1cf8 ? __ksymtab_rwsem_down_read_failed
	c02a1d00 ? __ksymtab_rwsem_down_write_failed
	c02a1d10 ? __ksymtab_rwsem_downgrade_wake
	c02a1d08 ? __ksymtab_rwsem_wake
	c01c5870 T rwsem_down_read_failed
	c01c5a20 T rwsem_down_write_failed
	c01c5cf0 T rwsem_downgrade_wake
	c01c5bd0 T rwsem_wake

When compiled for i386 SMP, I see:

	dhowells>nm vmlinux | grep 'rwsem\|__\(up\|down.*\)_\(read\|write\)'
	c01be49a t .text.lock.rwsem_spinlock
	c01bdf8c T __down_read
	c01be080 T __down_read_trylock
	c01be0f4 T __down_write
	c01be1ec T __down_write_trylock
	c01be3e4 T __downgrade_write
	c028c0f9 ? __kstrtab___down_read
	c028c120 ? __kstrtab___down_read_trylock
	c028c142 ? __kstrtab___down_write
	c028c160 ? __kstrtab___down_write_trylock
	c028c1c0 ? __kstrtab___downgrade_write
	c028c183 ? __kstrtab___up_read
	c028c19b ? __kstrtab___up_write
	c028c0e0 ? __kstrtab_init_rwsem
	c0295b80 ? __ksymtab___down_read
	c0295b88 ? __ksymtab___down_read_trylock
	c0295b90 ? __ksymtab___down_write
	c0295b98 ? __ksymtab___down_write_trylock
	c0295bb0 ? __ksymtab___downgrade_write
	c0295ba0 ? __ksymtab___up_read
	c0295ba8 ? __ksymtab___up_write
	c0295b78 ? __ksymtab_init_rwsem
	c01be264 T __up_read
	c01be2fc T __up_write
	c01bdf6c T init_rwsem

So I think I've got all the functions there and that they're all exported now.

David

diff -uNr linux-2.5.29/include/asm-i386/rwsem.h linux-rwsem-2529/include/asm-i386/rwsem.h
--- linux-2.5.29/include/asm-i386/rwsem.h	Mon Jul 29 08:26:56 2002
+++ linux-rwsem-2529/include/asm-i386/rwsem.h	Mon Jul 29 08:32:49 2002
@@ -118,6 +118,29 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	__s32 result, tmp;
+	__asm__ __volatile__(
+		"# beginning __down_read_trylock\n\t"
+		"  movl      %0,%1\n\t"
+		"1:\n\t"
+		"  movl	     %1,%2\n\t"
+		"  addl      %3,%2\n\t"
+		"  jle	     2f\n\t"
+LOCK_PREFIX	"  cmpxchgl  %2,%0\n\t"
+		"  jnz	     1b\n\t"
+		"2:\n\t"
+		"# ending __down_read_trylock\n\t"
+		: "+m"(sem->count), "=&a"(result), "=&r"(tmp)
+		: "i"(RWSEM_ACTIVE_READ_BIAS)
+		: "memory", "cc");
+	return result>=0 ? 1 : 0;
+}
+
+/*
  * lock for writing
  */
 static inline void __down_write(struct rw_semaphore *sem)
@@ -145,6 +168,19 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	signed long ret = cmpxchg(&sem->count,
+				  RWSEM_UNLOCKED_VALUE, 
+				  RWSEM_ACTIVE_WRITE_BIAS);
+	if (ret == RWSEM_UNLOCKED_VALUE)
+		return 1;
+	return 0;
+}
+
+/*
  * unlock after reading
  */
 static inline void __up_read(struct rw_semaphore *sem)
diff -uNr linux-2.5.29/include/linux/rwsem-spinlock.h linux-rwsem-2529/include/linux/rwsem-spinlock.h
--- linux-2.5.29/include/linux/rwsem-spinlock.h	Thu Jul 11 19:35:21 2002
+++ linux-rwsem-2529/include/linux/rwsem-spinlock.h	Mon Jul 29 08:32:49 2002
@@ -54,9 +54,12 @@
 
 extern void FASTCALL(init_rwsem(struct rw_semaphore *sem));
 extern void FASTCALL(__down_read(struct rw_semaphore *sem));
+extern int FASTCALL(__down_read_trylock(struct rw_semaphore *sem));
 extern void FASTCALL(__down_write(struct rw_semaphore *sem));
+extern int FASTCALL(__down_write_trylock(struct rw_semaphore *sem));
 extern void FASTCALL(__up_read(struct rw_semaphore *sem));
 extern void FASTCALL(__up_write(struct rw_semaphore *sem));
+extern void FASTCALL(__downgrade_write(struct rw_semaphore *sem));
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_RWSEM_SPINLOCK_H */
diff -uNr linux-2.5.29/include/linux/rwsem.h linux-rwsem-2529/include/linux/rwsem.h
--- linux-2.5.29/include/linux/rwsem.h	Mon Jul 29 08:26:57 2002
+++ linux-rwsem-2529/include/linux/rwsem.h	Mon Jul 29 08:32:49 2002
@@ -46,6 +46,18 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int down_read_trylock(struct rw_semaphore *sem)
+{
+	int ret;
+	rwsemtrace(sem,"Entering down_read_trylock");
+	ret = __down_read_trylock(sem);
+	rwsemtrace(sem,"Leaving down_read_trylock");
+	return ret;
+}
+
+/*
  * lock for writing
  */
 static inline void down_write(struct rw_semaphore *sem)
@@ -56,6 +68,18 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int down_write_trylock(struct rw_semaphore *sem)
+{
+	int ret;
+	rwsemtrace(sem,"Entering down_write_trylock");
+	ret = __down_write_trylock(sem);
+	rwsemtrace(sem,"Leaving down_write_trylock");
+	return ret;
+}
+
+/*
  * release a read lock
  */
 static inline void up_read(struct rw_semaphore *sem)
@@ -85,6 +109,5 @@
 	rwsemtrace(sem,"Leaving downgrade_write");
 }
 
-
 #endif /* __KERNEL__ */
 #endif /* _LINUX_RWSEM_H */
diff -uNr linux-2.5.29/lib/rwsem-spinlock.c linux-rwsem-2529/lib/rwsem-spinlock.c
--- linux-2.5.29/lib/rwsem-spinlock.c	Thu Jul 11 19:35:17 2002
+++ linux-rwsem-2529/lib/rwsem-spinlock.c	Mon Jul 29 08:32:49 2002
@@ -46,8 +46,9 @@
  *   - the 'waiting count' is non-zero
  * - the spinlock must be held by the caller
  * - woken process blocks are discarded from the list after having flags zeroised
+ * - writers are only woken if wakewrite is non-zero
  */
-static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem)
+static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int wakewrite)
 {
 	struct rwsem_waiter *waiter;
 	int woken;
@@ -56,7 +57,14 @@
 
 	waiter = list_entry(sem->wait_list.next,struct rwsem_waiter,list);
 
-	/* try to grant a single write lock if there's a writer at the front of the queue
+	if (!wakewrite) {
+		if (waiter->flags & RWSEM_WAITING_FOR_WRITE)
+			goto out;
+		goto dont_wake_writers;
+	}
+
+	/* if we are allowed to wake writers try to grant a single write lock if there's a
+	 * writer at the front of the queue
 	 * - we leave the 'waiting count' incremented to signify potential contention
 	 */
 	if (waiter->flags & RWSEM_WAITING_FOR_WRITE) {
@@ -68,16 +76,19 @@
 	}
 
 	/* grant an infinite number of read locks to the readers at the front of the queue */
+ dont_wake_writers:
 	woken = 0;
-	do {
+	while (waiter->flags&RWSEM_WAITING_FOR_READ) {
+		struct list_head *next = waiter->list.next;
+
 		list_del(&waiter->list);
 		waiter->flags = 0;
 		wake_up_process(waiter->task);
 		woken++;
 		if (list_empty(&sem->wait_list))
 			break;
-		waiter = list_entry(sem->wait_list.next,struct rwsem_waiter,list);
-	} while (waiter->flags&RWSEM_WAITING_FOR_READ);
+		waiter = list_entry(next,struct rwsem_waiter,list);
+	}
 
 	sem->activity += woken;
 
@@ -149,6 +160,28 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+int __down_read_trylock(struct rw_semaphore *sem)
+{
+	int ret = 0;
+	rwsemtrace(sem,"Entering __down_read_trylock");
+
+	spin_lock(&sem->wait_lock);
+
+	if (sem->activity>=0 && list_empty(&sem->wait_list)) {
+		/* granted */
+		sem->activity++;
+		ret = 1;
+	}
+
+	spin_unlock(&sem->wait_lock);
+
+	rwsemtrace(sem,"Leaving __down_read_trylock");
+	return ret;
+}
+
+/*
  * get a write lock on the semaphore
  * - note that we increment the waiting count anyway to indicate an exclusive lock
  */
@@ -195,6 +228,28 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+int __down_write_trylock(struct rw_semaphore *sem)
+{
+	int ret = 0;
+	rwsemtrace(sem,"Entering __down_write_trylock");
+
+	spin_lock(&sem->wait_lock);
+
+	if (sem->activity==0 && list_empty(&sem->wait_list)) {
+		/* granted */
+		sem->activity = -1;
+		ret = 1;
+	}
+
+	spin_unlock(&sem->wait_lock);
+
+	rwsemtrace(sem,"Leaving __down_write_trylock");
+	return ret;
+}
+
+/*
  * release a read lock on the semaphore
  */
 void __up_read(struct rw_semaphore *sem)
@@ -222,18 +277,40 @@
 
 	sem->activity = 0;
 	if (!list_empty(&sem->wait_list))
-		sem = __rwsem_do_wake(sem);
+		sem = __rwsem_do_wake(sem, 1);
 
 	spin_unlock(&sem->wait_lock);
 
 	rwsemtrace(sem,"Leaving __up_write");
 }
 
+/*
+ * downgrade a write lock into a read lock
+ * - just wake up any readers at the front of the queue
+ */
+void __downgrade_write(struct rw_semaphore *sem)
+{
+	rwsemtrace(sem,"Entering __rwsem_downgrade");
+
+	spin_lock(&sem->wait_lock);
+
+	sem->activity = 1;
+	if (!list_empty(&sem->wait_list))
+		sem = __rwsem_do_wake(sem,0);
+
+	spin_unlock(&sem->wait_lock);
+
+	rwsemtrace(sem,"Leaving __rwsem_downgrade");
+}
+
 EXPORT_SYMBOL(init_rwsem);
 EXPORT_SYMBOL(__down_read);
+EXPORT_SYMBOL(__down_read_trylock);
 EXPORT_SYMBOL(__down_write);
+EXPORT_SYMBOL(__down_write_trylock);
 EXPORT_SYMBOL(__up_read);
 EXPORT_SYMBOL(__up_write);
+EXPORT_SYMBOL(__downgrade_write);
 #if RWSEM_DEBUG
 EXPORT_SYMBOL(rwsemtrace);
 #endif
diff -uNr linux-2.5.29/lib/rwsem.c linux-rwsem-2529/lib/rwsem.c
--- linux-2.5.29/lib/rwsem.c	Mon Jul 29 08:26:57 2002
+++ linux-rwsem-2529/lib/rwsem.c	Mon Jul 29 08:35:47 2002
@@ -236,6 +236,7 @@
 EXPORT_SYMBOL_NOVERS(rwsem_down_read_failed);
 EXPORT_SYMBOL_NOVERS(rwsem_down_write_failed);
 EXPORT_SYMBOL_NOVERS(rwsem_wake);
+EXPORT_SYMBOL_NOVERS(rwsem_downgrade_wake);
 #if RWSEM_DEBUG
 EXPORT_SYMBOL(rwsemtrace);
 #endif

      reply	other threads:[~2002-07-29  8:09 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-07-28 18:24 [PATCH] missing rwsem bits Christoph Hellwig
2002-07-29  8:12 ` David Howells [this message]

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=17496.1027930376@warthog.cambridge.redhat.com \
    --to=dhowells@redhat.com \
    --cc=hch@lst.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@transmeta.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.