diff options
author | Ingo Molnar <mingo@elte.hu> | 2005-09-10 03:25:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-10 13:06:21 -0400 |
commit | fb1c8f93d869b34cacb8b8932e2b83d96a19d720 (patch) | |
tree | a006d078aa02e421a7dc4793c335308204859d36 /arch/alpha/kernel | |
parent | 4327edf6b8a7ac7dce144313947995538842d8fd (diff) |
[PATCH] spinlock consolidation
This patch (written by me and also containing many suggestions of Arjan van
de Ven) does a major cleanup of the spinlock code. It does the following
things:
- consolidates and enhances the spinlock/rwlock debugging code
- simplifies the asm/spinlock.h files
- encapsulates the raw spinlock type and moves generic spinlock
features (such as ->break_lock) into the generic code.
- cleans up the spinlock code hierarchy to get rid of the spaghetti.
Most notably there's now only a single variant of the debugging code,
located in lib/spinlock_debug.c. (previously we had one SMP debugging
variant per architecture, plus a separate generic one for UP builds)
Also, i've enhanced the rwlock debugging facility, it will now track
write-owners. There is new spinlock-owner/CPU-tracking on SMP builds too.
All locks have lockup detection now, which will work for both soft and hard
spin/rwlock lockups.
The arch-level include files now only contain the minimally necessary
subset of the spinlock code - all the rest that can be generalized now
lives in the generic headers:
include/asm-i386/spinlock_types.h | 16
include/asm-x86_64/spinlock_types.h | 16
I have also split up the various spinlock variants into separate files,
making it easier to see which does what. The new layout is:
SMP | UP
----------------------------|-----------------------------------
asm/spinlock_types_smp.h | linux/spinlock_types_up.h
linux/spinlock_types.h | linux/spinlock_types.h
asm/spinlock_smp.h | linux/spinlock_up.h
linux/spinlock_api_smp.h | linux/spinlock_api_up.h
linux/spinlock.h | linux/spinlock.h
/*
* here's the role of the various spinlock/rwlock related include files:
*
* on SMP builds:
*
* asm/spinlock_types.h: contains the raw_spinlock_t/raw_rwlock_t and the
* initializers
*
* linux/spinlock_types.h:
* defines the generic type and initializers
*
* asm/spinlock.h: contains the __raw_spin_*()/etc. lowlevel
* implementations, mostly inline assembly code
*
* (also included on UP-debug builds:)
*
* linux/spinlock_api_smp.h:
* contains the prototypes for the _spin_*() APIs.
*
* linux/spinlock.h: builds the final spin_*() APIs.
*
* on UP builds:
*
* linux/spinlock_type_up.h:
* contains the generic, simplified UP spinlock type.
* (which is an empty structure on non-debug builds)
*
* linux/spinlock_types.h:
* defines the generic type and initializers
*
* linux/spinlock_up.h:
* contains the __raw_spin_*()/etc. version of UP
* builds. (which are NOPs on non-debug, non-preempt
* builds)
*
* (included on UP-non-debug builds:)
*
* linux/spinlock_api_up.h:
* builds the _spin_*() APIs.
*
* linux/spinlock.h: builds the final spin_*() APIs.
*/
All SMP and UP architectures are converted by this patch.
arm, i386, ia64, ppc, ppc64, s390/s390x, x64 was build-tested via
crosscompilers. m32r, mips, sh, sparc, have not been tested yet, but should
be mostly fine.
From: Grant Grundler <grundler@parisc-linux.org>
Booted and lightly tested on a500-44 (64-bit, SMP kernel, dual CPU).
Builds 32-bit SMP kernel (not booted or tested). I did not try to build
non-SMP kernels. That should be trivial to fix up later if necessary.
I converted bit ops atomic_hash lock to raw_spinlock_t. Doing so avoids
some ugly nesting of linux/*.h and asm/*.h files. Those particular locks
are well tested and contained entirely inside arch specific code. I do NOT
expect any new issues to arise with them.
If someone does ever need to use debug/metrics with them, then they will
need to unravel this hairball between spinlocks, atomic ops, and bit ops
that exist only because parisc has exactly one atomic instruction: LDCW
(load and clear word).
From: "Luck, Tony" <tony.luck@intel.com>
ia64 fix
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Arjan van de Ven <arjanv@infradead.org>
Signed-off-by: Grant Grundler <grundler@parisc-linux.org>
Cc: Matthew Wilcox <willy@debian.org>
Signed-off-by: Hirokazu Takata <takata@linux-m32r.org>
Signed-off-by: Mikael Pettersson <mikpe@csd.uu.se>
Signed-off-by: Benoit Boissinot <benoit.boissinot@ens-lyon.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/alpha/kernel')
-rw-r--r-- | arch/alpha/kernel/alpha_ksyms.c | 9 | ||||
-rw-r--r-- | arch/alpha/kernel/smp.c | 172 |
2 files changed, 0 insertions, 181 deletions
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index fc5ef90c4fc9..24ae9a366073 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c | |||
@@ -185,15 +185,6 @@ EXPORT_SYMBOL(smp_num_cpus); | |||
185 | EXPORT_SYMBOL(smp_call_function); | 185 | EXPORT_SYMBOL(smp_call_function); |
186 | EXPORT_SYMBOL(smp_call_function_on_cpu); | 186 | EXPORT_SYMBOL(smp_call_function_on_cpu); |
187 | EXPORT_SYMBOL(_atomic_dec_and_lock); | 187 | EXPORT_SYMBOL(_atomic_dec_and_lock); |
188 | #ifdef CONFIG_DEBUG_SPINLOCK | ||
189 | EXPORT_SYMBOL(_raw_spin_unlock); | ||
190 | EXPORT_SYMBOL(debug_spin_lock); | ||
191 | EXPORT_SYMBOL(debug_spin_trylock); | ||
192 | #endif | ||
193 | #ifdef CONFIG_DEBUG_RWLOCK | ||
194 | EXPORT_SYMBOL(_raw_write_lock); | ||
195 | EXPORT_SYMBOL(_raw_read_lock); | ||
196 | #endif | ||
197 | EXPORT_SYMBOL(cpu_present_mask); | 188 | EXPORT_SYMBOL(cpu_present_mask); |
198 | #endif /* CONFIG_SMP */ | 189 | #endif /* CONFIG_SMP */ |
199 | 190 | ||
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index e211aa7404e6..da0be3465791 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c | |||
@@ -989,175 +989,3 @@ flush_icache_user_range(struct vm_area_struct *vma, struct page *page, | |||
989 | 989 | ||
990 | preempt_enable(); | 990 | preempt_enable(); |
991 | } | 991 | } |
992 | |||
993 | #ifdef CONFIG_DEBUG_SPINLOCK | ||
994 | void | ||
995 | _raw_spin_unlock(spinlock_t * lock) | ||
996 | { | ||
997 | mb(); | ||
998 | lock->lock = 0; | ||
999 | |||
1000 | lock->on_cpu = -1; | ||
1001 | lock->previous = NULL; | ||
1002 | lock->task = NULL; | ||
1003 | lock->base_file = "none"; | ||
1004 | lock->line_no = 0; | ||
1005 | } | ||
1006 | |||
1007 | void | ||
1008 | debug_spin_lock(spinlock_t * lock, const char *base_file, int line_no) | ||
1009 | { | ||
1010 | long tmp; | ||
1011 | long stuck; | ||
1012 | void *inline_pc = __builtin_return_address(0); | ||
1013 | unsigned long started = jiffies; | ||
1014 | int printed = 0; | ||
1015 | int cpu = smp_processor_id(); | ||
1016 | |||
1017 | stuck = 1L << 30; | ||
1018 | try_again: | ||
1019 | |||
1020 | /* Use sub-sections to put the actual loop at the end | ||
1021 | of this object file's text section so as to perfect | ||
1022 | branch prediction. */ | ||
1023 | __asm__ __volatile__( | ||
1024 | "1: ldl_l %0,%1\n" | ||
1025 | " subq %2,1,%2\n" | ||
1026 | " blbs %0,2f\n" | ||
1027 | " or %0,1,%0\n" | ||
1028 | " stl_c %0,%1\n" | ||
1029 | " beq %0,3f\n" | ||
1030 | "4: mb\n" | ||
1031 | ".subsection 2\n" | ||
1032 | "2: ldl %0,%1\n" | ||
1033 | " subq %2,1,%2\n" | ||
1034 | "3: blt %2,4b\n" | ||
1035 | " blbs %0,2b\n" | ||
1036 | " br 1b\n" | ||
1037 | ".previous" | ||
1038 | : "=r" (tmp), "=m" (lock->lock), "=r" (stuck) | ||
1039 | : "m" (lock->lock), "2" (stuck) : "memory"); | ||
1040 | |||
1041 | if (stuck < 0) { | ||
1042 | printk(KERN_WARNING | ||
1043 | "%s:%d spinlock stuck in %s at %p(%d)" | ||
1044 | " owner %s at %p(%d) %s:%d\n", | ||
1045 | base_file, line_no, | ||
1046 | current->comm, inline_pc, cpu, | ||
1047 | lock->task->comm, lock->previous, | ||
1048 | lock->on_cpu, lock->base_file, lock->line_no); | ||
1049 | stuck = 1L << 36; | ||
1050 | printed = 1; | ||
1051 | goto try_again; | ||
1052 | } | ||
1053 | |||
1054 | /* Exiting. Got the lock. */ | ||
1055 | lock->on_cpu = cpu; | ||
1056 | lock->previous = inline_pc; | ||
1057 | lock->task = current; | ||
1058 | lock->base_file = base_file; | ||
1059 | lock->line_no = line_no; | ||
1060 | |||
1061 | if (printed) { | ||
1062 | printk(KERN_WARNING | ||
1063 | "%s:%d spinlock grabbed in %s at %p(%d) %ld ticks\n", | ||
1064 | base_file, line_no, current->comm, inline_pc, | ||
1065 | cpu, jiffies - started); | ||
1066 | } | ||
1067 | } | ||
1068 | |||
1069 | int | ||
1070 | debug_spin_trylock(spinlock_t * lock, const char *base_file, int line_no) | ||
1071 | { | ||
1072 | int ret; | ||
1073 | if ((ret = !test_and_set_bit(0, lock))) { | ||
1074 | lock->on_cpu = smp_processor_id(); | ||
1075 | lock->previous = __builtin_return_address(0); | ||
1076 | lock->task = current; | ||
1077 | } else { | ||
1078 | lock->base_file = base_file; | ||
1079 | lock->line_no = line_no; | ||
1080 | } | ||
1081 | return ret; | ||
1082 | } | ||
1083 | #endif /* CONFIG_DEBUG_SPINLOCK */ | ||
1084 | |||
1085 | #ifdef CONFIG_DEBUG_RWLOCK | ||
1086 | void _raw_write_lock(rwlock_t * lock) | ||
1087 | { | ||
1088 | long regx, regy; | ||
1089 | int stuck_lock, stuck_reader; | ||
1090 | void *inline_pc = __builtin_return_address(0); | ||
1091 | |||
1092 | try_again: | ||
1093 | |||
1094 | stuck_lock = 1<<30; | ||
1095 | stuck_reader = 1<<30; | ||
1096 | |||
1097 | __asm__ __volatile__( | ||
1098 | "1: ldl_l %1,%0\n" | ||
1099 | " blbs %1,6f\n" | ||
1100 | " blt %1,8f\n" | ||
1101 | " mov 1,%1\n" | ||
1102 | " stl_c %1,%0\n" | ||
1103 | " beq %1,6f\n" | ||
1104 | "4: mb\n" | ||
1105 | ".subsection 2\n" | ||
1106 | "6: blt %3,4b # debug\n" | ||
1107 | " subl %3,1,%3 # debug\n" | ||
1108 | " ldl %1,%0\n" | ||
1109 | " blbs %1,6b\n" | ||
1110 | "8: blt %4,4b # debug\n" | ||
1111 | " subl %4,1,%4 # debug\n" | ||
1112 | " ldl %1,%0\n" | ||
1113 | " blt %1,8b\n" | ||
1114 | " br 1b\n" | ||
1115 | ".previous" | ||
1116 | : "=m" (*(volatile int *)lock), "=&r" (regx), "=&r" (regy), | ||
1117 | "=&r" (stuck_lock), "=&r" (stuck_reader) | ||
1118 | : "m" (*(volatile int *)lock), "3" (stuck_lock), "4" (stuck_reader) : "memory"); | ||
1119 | |||
1120 | if (stuck_lock < 0) { | ||
1121 | printk(KERN_WARNING "write_lock stuck at %p\n", inline_pc); | ||
1122 | goto try_again; | ||
1123 | } | ||
1124 | if (stuck_reader < 0) { | ||
1125 | printk(KERN_WARNING "write_lock stuck on readers at %p\n", | ||
1126 | inline_pc); | ||
1127 | goto try_again; | ||
1128 | } | ||
1129 | } | ||
1130 | |||
1131 | void _raw_read_lock(rwlock_t * lock) | ||
1132 | { | ||
1133 | long regx; | ||
1134 | int stuck_lock; | ||
1135 | void *inline_pc = __builtin_return_address(0); | ||
1136 | |||
1137 | try_again: | ||
1138 | |||
1139 | stuck_lock = 1<<30; | ||
1140 | |||
1141 | __asm__ __volatile__( | ||
1142 | "1: ldl_l %1,%0;" | ||
1143 | " blbs %1,6f;" | ||
1144 | " subl %1,2,%1;" | ||
1145 | " stl_c %1,%0;" | ||
1146 | " beq %1,6f;" | ||
1147 | "4: mb\n" | ||
1148 | ".subsection 2\n" | ||
1149 | "6: ldl %1,%0;" | ||
1150 | " blt %2,4b # debug\n" | ||
1151 | " subl %2,1,%2 # debug\n" | ||
1152 | " blbs %1,6b;" | ||
1153 | " br 1b\n" | ||
1154 | ".previous" | ||
1155 | : "=m" (*(volatile int *)lock), "=&r" (regx), "=&r" (stuck_lock) | ||
1156 | : "m" (*(volatile int *)lock), "2" (stuck_lock) : "memory"); | ||
1157 | |||
1158 | if (stuck_lock < 0) { | ||
1159 | printk(KERN_WARNING "read_lock stuck at %p\n", inline_pc); | ||
1160 | goto try_again; | ||
1161 | } | ||
1162 | } | ||
1163 | #endif /* CONFIG_DEBUG_RWLOCK */ | ||