[PATCH 1/3] bit mutexes

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Mikulas Patocka
Date: Sunday, October 5, 2008 - 3:14 pm

A bit mutex implementation.

Bit mutex is a space-efficient mutex that consumes exactly one bit in
the apropriate structure (if mutex debugging is turned off).  Bit mutex
is implemented as a bit in unsigned long field. Other bits in the field
may be used for other purposes, if test/set/clear_bit functions are used
to manipulate them. There is no wait queue in the structure containing
the bit mutex; hashed wait queues for waiting on bits are used.

Additional structure struct bit_mutex is needed, it contains lock
debugging & dependency information. When the kernel is compiled without
lock debugging, this structure is empty.

Bit mutexes are used with functions
bit_mutex_init
bit_mutex_lock
bit_mutex_unlock
bit_mutex_is_locked
These functions take 3 arguments: pointer to the unsigned long field,
the bit position and pointer to struct bit_mutex.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>

---
 include/linux/bit-mutex.h |   98 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/wait.h      |    8 +++
 kernel/Makefile           |    2 
 kernel/bit-mutex-debug.c  |   55 +++++++++++++++++++++++++
 kernel/wait.c             |    7 +++
 5 files changed, 169 insertions(+), 1 deletion(-)

Index: linux-2.6.27-rc8-devel/include/linux/bit-mutex.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.27-rc8-devel/include/linux/bit-mutex.h	2008-10-05 19:58:30.000000000 +0200
@@ -0,0 +1,98 @@
+#ifndef __LINUX_BIT_MUTEX_H
+#define __LINUX_BIT_MUTEX_H
+
+#include <linux/bitops.h>
+#include <linux/lockdep.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+
+struct bit_mutex {
+#ifdef CONFIG_DEBUG_MUTEXES
+	unsigned long		*field;
+	int 			bit;
+	struct thread_info	*owner;
+	const char		*name;
+	void			*magic;
+#endif
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	struct lockdep_map	dep_map;
+#endif
+};
+
+#ifndef CONFIG_DEBUG_MUTEXES
+
+static inline void bit_mutex_init(unsigned long *field, int bit, struct bit_mutex *mtx)
+{
+	clear_bit(bit, field);
+	smp_mb__after_clear_bit();
+}
+
+static inline void bit_mutex_lock(unsigned long *field, int bit, struct bit_mutex *mtx)
+{
+	wait_on_bit_lock(field, bit, wait_action_schedule, TASK_UNINTERRUPTIBLE);
+}
+
+static inline void bit_mutex_unlock(unsigned long *field, int bit, struct bit_mutex *mtx)
+{
+	smp_mb__before_clear_bit();
+	clear_bit(bit, field);
+	smp_mb__after_clear_bit();
+	wake_up_bit(field, bit);
+}
+
+static inline int bit_mutex_is_locked(unsigned long *field, int bit, struct bit_mutex *mtx)
+{
+	return test_bit(bit, field);
+}
+
+#define __DEBUG_BIT_MUTEX_INITIALIZER(field, bit, mtx)
+
+#else
+
+void __bit_mutex_init(unsigned long *field, int bit, struct bit_mutex *mtx, const char *name, struct lock_class_key *key);
+
+#define bit_mutex_init(field, bit, mtx)				\
+do {								\
+	static struct lock_class_key __key;			\
+	__bit_mutex_init(field, bit, mtx, #mtx, &__key);	\
+} while (0)
+
+void __bit_mutex_lock(unsigned long *field, int bit, struct bit_mutex *mtx, int subclass);
+
+#define bit_mutex_lock(field, bit, mtx)				\
+	__bit_mutex_lock(field, bit, mtx, 0)
+
+void __bit_mutex_unlock(unsigned long *field, int bit, struct bit_mutex *mtx, int subclass);
+
+#define bit_mutex_unlock(field, bit, mtx)			\
+	__bit_mutex_unlock(field, bit, mtx, 0)
+
+int bit_mutex_is_locked(unsigned long *field, int bit, struct bit_mutex *mtx);
+
+#define __DEBUG_BIT_MUTEX_INITIALIZER(field_, bit_, mtx)	\
+	.magic = &(mtx),					\
+	.field = (field_),					\
+	.bit = (bit_)
+
+#endif
+
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+
+#define __DEP_MAP_BIT_MUTEX_INITIALIZER(field, bit, mtx)	\
+	, .dep_map = { .name = #mtx }
+
+#else
+
+#define __DEP_MAP_BIT_MUTEX_INITIALIZER(field, bit, mtx)
+
+#endif
+
+
+#define __BIT_MUTEX_INITIALIZER(field, bit, mtx)		\
+	{							\
+		__DEBUG_BIT_MUTEX_INITIALIZER(field, bit, mtx)	\
+		__DEP_MAP_BIT_MUTEX_INITIALIZER(field, bit, mtx)\
+	}
+
+#endif
Index: linux-2.6.27-rc8-devel/include/linux/wait.h
===================================================================
--- linux-2.6.27-rc8-devel.orig/include/linux/wait.h	2008-10-04 13:40:46.000000000 +0200
+++ linux-2.6.27-rc8-devel/include/linux/wait.h	2008-10-04 13:41:21.000000000 +0200
@@ -513,7 +513,13 @@ static inline int wait_on_bit_lock(void 
 		return 0;
 	return out_of_line_wait_on_bit_lock(word, bit, action, mode);
 }
-	
+
+/**
+ * wait_action_schedule - this function can be passed to wait_on_bit or
+ * wait_on_bit_lock and it will call just schedule().
+ */
+int wait_action_schedule(void *);
+
 #endif /* __KERNEL__ */
 
 #endif
Index: linux-2.6.27-rc8-devel/kernel/wait.c
===================================================================
--- linux-2.6.27-rc8-devel.orig/kernel/wait.c	2008-10-04 13:37:24.000000000 +0200
+++ linux-2.6.27-rc8-devel/kernel/wait.c	2008-10-04 13:38:21.000000000 +0200
@@ -251,3 +251,10 @@ wait_queue_head_t *bit_waitqueue(void *w
 	return &zone->wait_table[hash_long(val, zone->wait_table_bits)];
 }
 EXPORT_SYMBOL(bit_waitqueue);
+
+int wait_action_schedule(void *word)
+{
+	schedule();
+	return 0;
+}
+EXPORT_SYMBOL(wait_action_schedule);
Index: linux-2.6.27-rc8-devel/kernel/Makefile
===================================================================
--- linux-2.6.27-rc8-devel.orig/kernel/Makefile	2008-10-05 14:03:24.000000000 +0200
+++ linux-2.6.27-rc8-devel/kernel/Makefile	2008-10-05 14:11:25.000000000 +0200
@@ -17,6 +17,7 @@ ifdef CONFIG_FTRACE
 # Do not trace debug files and internal ftrace files
 CFLAGS_REMOVE_lockdep.o = -pg
 CFLAGS_REMOVE_lockdep_proc.o = -pg
+CFLAGS_REMOVE_bit-mutex-debug.o = -pg
 CFLAGS_REMOVE_mutex-debug.o = -pg
 CFLAGS_REMOVE_rtmutex-debug.o = -pg
 CFLAGS_REMOVE_cgroup-debug.o = -pg
@@ -29,6 +30,7 @@ obj-$(CONFIG_SYSCTL_SYSCALL_CHECK) += sy
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
 obj-y += time/
 obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o
+obj-$(CONFIG_DEBUG_MUTEXES) += bit-mutex-debug.o
 obj-$(CONFIG_LOCKDEP) += lockdep.o
 ifeq ($(CONFIG_PROC_FS),y)
 obj-$(CONFIG_LOCKDEP) += lockdep_proc.o
Index: linux-2.6.27-rc8-devel/kernel/bit-mutex-debug.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.27-rc8-devel/kernel/bit-mutex-debug.c	2008-10-05 19:12:06.000000000 +0200
@@ -0,0 +1,55 @@
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/debug_locks.h>
+#include <linux/bit-mutex.h>
+
+void __bit_mutex_init(unsigned long *field, int bit, struct bit_mutex *mtx, const char *name, struct lock_class_key *key)
+{
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	debug_check_no_locks_freed((void *)mtx, sizeof(*mtx));
+	lockdep_init_map(&mtx->dep_map, name, key, 0);
+#endif
+	mtx->field = field;
+	mtx->bit = bit;
+	mtx->owner = NULL;
+	mtx->magic = mtx;
+	clear_bit(bit, field);
+	smp_mb__after_clear_bit();
+}
+EXPORT_SYMBOL(__bit_mutex_init);
+
+void __bit_mutex_lock(unsigned long *field, int bit, struct bit_mutex *mtx, int subclass)
+{
+	DEBUG_LOCKS_WARN_ON(mtx->magic != mtx);
+	DEBUG_LOCKS_WARN_ON(field != mtx->field);
+	DEBUG_LOCKS_WARN_ON(bit != mtx->bit);
+	mutex_acquire(&mtx->dep_map, subclass, 0, _RET_IP_);
+	wait_on_bit_lock(field, bit, wait_action_schedule, TASK_UNINTERRUPTIBLE);
+	lock_acquired(&mtx->dep_map);
+	mtx->owner = current_thread_info();
+}
+EXPORT_SYMBOL(__bit_mutex_lock);
+
+void __bit_mutex_unlock(unsigned long *field, int bit, struct bit_mutex *mtx, int nested)
+{
+	DEBUG_LOCKS_WARN_ON(mtx->magic != mtx);
+	DEBUG_LOCKS_WARN_ON(mtx->owner != current_thread_info());
+	DEBUG_LOCKS_WARN_ON(mtx->field != field);
+	DEBUG_LOCKS_WARN_ON(mtx->bit != bit);
+	mtx->owner = NULL;
+	mutex_release(&mtx->dep_map, nested, _RET_IP_);
+	smp_mb__before_clear_bit();
+	clear_bit(bit, field);
+	smp_mb__after_clear_bit();
+	wake_up_bit(field, bit);
+}
+EXPORT_SYMBOL(__bit_mutex_unlock);
+
+int bit_mutex_is_locked(unsigned long *field, int bit, struct bit_mutex *mtx)
+{
+	DEBUG_LOCKS_WARN_ON(mtx->magic != mtx);
+	DEBUG_LOCKS_WARN_ON(field != mtx->field);
+	DEBUG_LOCKS_WARN_ON(bit != mtx->bit);
+	return test_bit(bit, field);
+}
+EXPORT_SYMBOL(bit_mutex_is_locked);
--
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[PATCH] Memory management livelock, Mikulas Patocka, (Mon Sep 22, 2:10 pm)
Re: [PATCH] Memory management livelock, Andrew Morton, (Mon Sep 22, 5:48 pm)
Re: [PATCH] Memory management livelock, Mikulas Patocka, (Tue Sep 23, 3:34 pm)
Re: [PATCH] Memory management livelock, Andrew Morton, (Tue Sep 23, 3:49 pm)
Re: [PATCH] Memory management livelock, Mikulas Patocka, (Tue Sep 23, 4:11 pm)
Re: [PATCH] Memory management livelock, Andrew Morton, (Tue Sep 23, 4:46 pm)
Re: [PATCH] Memory management livelock, Mikulas Patocka, (Wed Sep 24, 11:50 am)
[PATCH 1/3] Memory management livelock, Mikulas Patocka, (Wed Sep 24, 11:51 am)
[PATCH 2/3] Memory management livelock, Mikulas Patocka, (Wed Sep 24, 11:52 am)
[PATCH 3/3] Memory management livelock, Mikulas Patocka, (Wed Sep 24, 11:53 am)
Re: [PATCH 2/3] Memory management livelock, Andrew Morton, (Wed Oct 1, 10:54 pm)
Re: [PATCH] Memory management livelock, Nick Piggin, (Thu Oct 2, 7:32 pm)
Re: [PATCH] Memory management livelock, Andrew Morton, (Thu Oct 2, 7:40 pm)
Re: [PATCH] Memory management livelock, Nick Piggin, (Thu Oct 2, 7:54 pm)
Re: [PATCH] Memory management livelock, Nick Piggin, (Thu Oct 2, 7:59 pm)
Re: [PATCH] Memory management livelock, Andrew Morton, (Thu Oct 2, 8:14 pm)
Re: [PATCH] Memory management livelock, Nick Piggin, (Thu Oct 2, 8:47 pm)
Re: [PATCH] Memory management livelock, Andrew Morton, (Thu Oct 2, 8:56 pm)
Re: [PATCH] Memory management livelock, Nick Piggin, (Thu Oct 2, 9:07 pm)
Re: [PATCH] Memory management livelock, Andrew Morton, (Thu Oct 2, 9:17 pm)
Re: [PATCH] Memory management livelock, Nick Piggin, (Thu Oct 2, 9:29 pm)
Re: [PATCH] Memory management livelock, Mikulas Patocka, (Fri Oct 3, 4:26 am)
Re: [PATCH] Memory management livelock, Mikulas Patocka, (Fri Oct 3, 4:43 am)
Re: [PATCH] Memory management livelock, Nick Piggin, (Fri Oct 3, 5:27 am)
Re: [PATCH] Memory management livelock, Nick Piggin, (Fri Oct 3, 5:31 am)
Re: [PATCH] Memory management livelock, Mikulas Patocka, (Fri Oct 3, 6:50 am)
Re: [PATCH] Memory management livelock, Mikulas Patocka, (Fri Oct 3, 6:53 am)
Re: [PATCH] Memory management livelock, Alasdair G Kergon, (Fri Oct 3, 7:36 am)
Re: [PATCH] Memory management livelock, Alasdair G Kergon, (Fri Oct 3, 7:50 am)
[PATCH 1/3] bit mutexes, Mikulas Patocka, (Sun Oct 5, 3:14 pm)
[PATCH 2/3] Fix fsync livelock, Mikulas Patocka, (Sun Oct 5, 3:14 pm)
[PATCH 3/3] Fix fsync-vs-write misbehavior, Mikulas Patocka, (Sun Oct 5, 3:16 pm)
Re: [PATCH 2/3] Fix fsync livelock, Arjan van de Ven, (Sun Oct 5, 3:33 pm)
Re: [PATCH 2/3] Fix fsync livelock, Mikulas Patocka, (Sun Oct 5, 4:02 pm)
Re: [PATCH 2/3] Fix fsync livelock, Arjan van de Ven, (Sun Oct 5, 4:07 pm)
Re: [PATCH 2/3] Fix fsync livelock, Mikulas Patocka, (Sun Oct 5, 4:18 pm)
Re: [PATCH 2/3] Fix fsync livelock, Arjan van de Ven, (Sun Oct 5, 4:28 pm)
Re: [PATCH 2/3] Fix fsync livelock, Mikulas Patocka, (Sun Oct 5, 5:01 pm)
Re: [PATCH 2/3] Fix fsync livelock, Arjan van de Ven, (Sun Oct 5, 5:30 pm)
Re: [PATCH 2/3] Fix fsync livelock, Dave Chinner, (Sun Oct 5, 7:51 pm)
Re: [PATCH 2/3] Fix fsync livelock, Mikulas Patocka, (Sun Oct 5, 8:30 pm)
Re: [PATCH 2/3] Fix fsync livelock, Arjan van de Ven, (Sun Oct 5, 9:20 pm)
Re: [PATCH 2/3] Fix fsync livelock, Mikulas Patocka, (Mon Oct 6, 6:00 am)
Re: [PATCH 2/3] Fix fsync livelock, Arjan van de Ven, (Mon Oct 6, 6:50 am)
Re: [PATCH 2/3] Fix fsync livelock, Mikulas Patocka, (Mon Oct 6, 1:44 pm)
Re: [PATCH 2/3] Fix fsync livelock, Pavel Machek, (Wed Oct 8, 3:56 am)
[PATCH] documentation: explain memory barriers, Randy Dunlap, (Wed Oct 8, 6:12 pm)
Re: [PATCH] documentation: explain memory barriers, Chris Snook, (Wed Oct 8, 6:17 pm)
Re: [PATCH] documentation: explain memory barriers, Andrew Morton, (Wed Oct 8, 6:31 pm)
Re: [PATCH] documentation: explain memory barriers, Valdis.Kletnieks, (Wed Oct 8, 6:50 pm)
Re: [PATCH] documentation: explain memory barriers, Chris Snook, (Wed Oct 8, 10:51 pm)
Re: [PATCH] documentation: explain memory barriers, Valdis.Kletnieks, (Wed Oct 8, 11:52 pm)
Re: [PATCH] documentation: explain memory barriers, Ben Hutchings, (Thu Oct 9, 2:58 am)
Re: [PATCH] documentation: explain memory barriers, Nick Piggin, (Thu Oct 9, 10:29 am)
Re: [PATCH] documentation: explain memory barriers, Nick Piggin, (Thu Oct 9, 10:35 am)
Re: [PATCH] documentation: explain memory barriers, Nick Piggin, (Thu Oct 9, 2:27 pm)