Allow inlined spinlocks again V5
Subsystems (7)
cover Allow inlined spinlocks again V5
This patch set allows to have inlined spinlocks again.
V2: rewritten from scratch - now also with readable code
V3: removed macro to generate out-of-line spinlock variants since that
would break ctags. As requested by Arnd Bergmann.
V4: allow architectures to specify for each lock/unlock variant if
it should be kept out-of-line or inlined.
V5: simplify ifdefs as pointed out by Linus. Fix architecture compile
breakages caused by this change.
Linus, Ingo, do you still have objections?
---
The rationale behind this is that function calls on at least s390 are expensive.
If one considers that server kernels are usually compiled with !CONFIG_PREEMPT a simple spin_lock is just a compare and swap loop. The extra overhead for a function call is significant.
With inlined spinlocks overall cpu usage gets reduced by 1%-5% on s390. These numbers were taken with some network benchmarks. However I expect any workload that calls frequently into the kernel and which grabs a few locks to perform better.
The implementation is straight forward: move the function bodies of the locking functions to static inline functions and place them in a header file.
By default all locking code remains out-of-line. An architecture can specify
#define __spin_lock_is_small
in arch/<whatever>/include/asm/spinlock.h to force inlining of a locking function.
defconfig cross compile tested for alpha, arm, x86, x86_64, ia64, m68k, m68knommu, mips, powerpc, powerpc64, sparc64, s390, s390x.
PATCH 1/8 powerpc: rename __spin_try_lock() and friends
From: Heiko Carstens <[email protected]>
Rename __spin_try_trylock() and friends to arch_spin_try_lock() etc.
Needed to avoid namespace conflicts when the common code function bodies of _spin_try_lock() etc. are moved to a header file where the function name would be __spin_try_lock().
--- arch/powerpc/include/asm/spinlock.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
arch/powerpc/include/asm/spinlock.h +10 -10
@@ -54,7 +54,7 @@* This returns the old value in the lock, so we succeeded * in getting the lock if the return value is 0. */ -static inline unsigned long __spin_trylock (raw_spinlock_t *lock) +static inline unsigned long arch_spin_trylock (raw_spinlock_t *lock) {unsigned long tmp, token;
@@ -76,7 +76,7 @@ static inline unsigned long __spin_trylostatic inline int __raw_spin_trylock (raw_spinlock_t *lock) {CLEAR_IO_SYNC ; -return __spin_trylock (lock) ==0 ; +return arch_spin_trylock (lock) ==0 ; }/*
@@ -108,7 +108,7 @@ static inline void __raw_spin_lock(raw_s {CLEAR_IO_SYNC ;while (1 ) { -if (likely (__spin_trylock (lock) ==0 )) +if (likely (arch_spin_trylock (lock) ==0 ))break ; do { HMT_low();
@@ -126,7 +126,7 @@ void __raw_spin_lock_flags(raw_spinlock_CLEAR_IO_SYNC ;while (1 ) { -if (likely (__spin_trylock (lock) ==0 )) +if (likely (arch_spin_trylock (lock) ==0 ))break ;local_save_flags (flags_dis);local_irq_restore (flags);
@@ -181,7 +181,7 @@ extern void __raw_spin_unlock_wait(raw_s* This returns the old value in the lock + 1, * so we got a read lock if the return value is > 0. */ -static inline long __read_trylock (raw_rwlock_t *rw) +static inline long arch_read_trylock (raw_rwlock_t *rw) {long tmp;
@@ -205,7 +205,7 @@ static inline long __read_trylock(raw_rw* This returns the old value in the lock, * so we got the write lock if the return value is 0. */ -static inline long __write_trylock (raw_rwlock_t *rw) +static inline long arch_write_trylock (raw_rwlock_t *rw) {long tmp, token;
@@ -228,7 +228,7 @@ static inline long __write_trylock(raw_rstatic inline void __raw_read_lock (raw_rwlock_t *rw) {while (1 ) { -if (likely (__read_trylock (rw) >0 )) +if (likely (arch_read_trylock (rw) >0 ))break ; do { HMT_low();
@@ -242,7 +242,7 @@ static inline void __raw_read_lock(raw_rstatic inline void __raw_write_lock (raw_rwlock_t *rw) {while (1 ) { -if (likely (__write_trylock (rw) ==0 )) +if (likely (arch_write_trylock (rw) ==0 ))break ; do { HMT_low();
@@ -255,12 +255,12 @@ static inline void __raw_write_lock(raw_static inline int __raw_read_trylock (raw_rwlock_t *rw) { -return __read_trylock (rw) >0 ; +return arch_read_trylock (rw) >0 ; }static inline int __raw_write_trylock (raw_rwlock_t *rw) { -return __write_trylock (rw) ==0 ; +return arch_write_trylock (rw) ==0 ; }static inline void __raw_read_unlock (raw_rwlock_t *rw)
PATCH 2/8 sparc: rename __spin_try_lock() and friends
In reply to Heiko CarstensFrom: Heiko Carstens <[email protected]>
Rename __spin_try_trylock() and friends to arch_spin_try_lock() etc.
Needed to avoid namespace conflicts when the common code function bodies of _spin_try_lock() etc. are moved to a header file where the function name would be __spin_try_lock().
--- arch/sparc/include/asm/spinlock_32.h | 12 ++++++------ arch/sparc/include/asm/spinlock_64.h | 28 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 20 deletions(-)
arch/sparc/include/asm/spinlock_32.h +6 -6
@@ -76,7 +76,7 @@ static inline void __raw_spin_unlock(raw* * Unfortunately this scheme limits us to ~16,000,000 cpus. */ -static inline void __read_lock (raw_rwlock_t *rw) +static inline void arch_read_lock (raw_rwlock_t *rw) { registerraw_rwlock_t *lp asm("g1" ); lp = rw;
@@ -92,11 +92,11 @@ static inline void __read_lock(raw_rwloc#define __raw_read_lock (lock) \ do { unsigned long flags; \ local_irq_save(flags); \ - __read_lock(lock); \ + arch_read_lock(lock); \ local_irq_restore(flags); \ } while(0) -static inline void __read_unlock (raw_rwlock_t *rw) +static inline void arch_read_unlock (raw_rwlock_t *rw) { registerraw_rwlock_t *lp asm("g1" ); lp = rw;
@@ -112,7 +112,7 @@ static inline void __read_unlock(raw_rwl#define __raw_read_unlock (lock) \ do { unsigned long flags; \ local_irq_save(flags); \ - __read_unlock(lock); \ + arch_read_unlock(lock); \ local_irq_restore(flags); \ } while(0)
@@ -150,7 +150,7 @@ static inline int __raw_write_trylock(rareturn (val ==0 ); } -static inline int __read_trylock (raw_rwlock_t *rw) +static inline int arch_read_trylock (raw_rwlock_t *rw) { registerraw_rwlock_t *lp asm("g1" ); registerint res asm("o0" );
@@ -169,7 +169,7 @@ static inline int __read_trylock(raw_rwl ({unsigned long flags; \int res; \local_irq_save (flags); \ - res =__read_trylock (lock); \ + res =arch_read_trylock (lock); \local_irq_restore (flags); \ res; \ })
arch/sparc/include/asm/spinlock_64.h +14 -14
@@ -92,7 +92,7 @@ static inline void __raw_spin_lock_flags/* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */ -static void inline __read_lock (raw_rwlock_t *lock) +static void inline arch_read_lock (raw_rwlock_t *lock) {unsigned long tmp1, tmp2;
@@ -115,7 +115,7 @@ static void inline __read_lock(raw_rwloc : "memory"); } -static int inline __read_trylock (raw_rwlock_t *lock) +static int inline arch_read_trylock (raw_rwlock_t *lock) {int tmp1, tmp2;
@@ -136,7 +136,7 @@ static int inline __read_trylock(raw_rwlreturn tmp1; } -static void inline __read_unlock (raw_rwlock_t *lock) +static void inline arch_read_unlock (raw_rwlock_t *lock) {unsigned long tmp1, tmp2;
@@ -152,7 +152,7 @@ static void inline __read_unlock(raw_rwl : "memory"); } -static void inline __write_lock (raw_rwlock_t *lock) +static void inline arch_write_lock (raw_rwlock_t *lock) {unsigned long mask, tmp1, tmp2;
@@ -177,7 +177,7 @@ static void inline __write_lock(raw_rwlo : "memory"); } -static void inline __write_unlock (raw_rwlock_t *lock) +static void inline arch_write_unlock (raw_rwlock_t *lock) { __asm__ __volatile__( " stw %%g0, [%0]"
@@ -186,7 +186,7 @@ static void inline __write_unlock(raw_rw : "memory"); } -static int inline __write_trylock (raw_rwlock_t *lock) +static int inline arch_write_trylock (raw_rwlock_t *lock) {unsigned long mask, tmp1, tmp2, result;
@@ -210,14 +210,14 @@ static int inline __write_trylock(raw_rwreturn result; } -#define __raw_read_lock (p) __read_lock(p) -#define __raw_read_lock_flags (p, f) __read_lock(p) -#define __raw_read_trylock (p) __read_trylock(p) -#define __raw_read_unlock (p) __read_unlock(p) -#define __raw_write_lock (p) __write_lock(p) -#define __raw_write_lock_flags (p, f) __write_lock(p) -#define __raw_write_unlock (p) __write_unlock(p) -#define __raw_write_trylock (p) __write_trylock(p) +#define __raw_read_lock (p) arch_read_lock(p) +#define __raw_read_lock_flags (p, f) arch_read_lock(p) +#define __raw_read_trylock (p) arch_read_trylock(p) +#define __raw_read_unlock (p) arch_read_unlock(p) +#define __raw_write_lock (p) arch_write_lock(p) +#define __raw_write_lock_flags (p, f) arch_write_lock(p) +#define __raw_write_unlock (p) arch_write_unlock(p) +#define __raw_write_trylock (p) arch_write_trylock(p)#define __raw_read_can_lock (rw) (!((rw)->lock & 0x80000000UL))#define __raw_write_can_lock (rw) (!(rw)->lock)
Re: [patch 2/8] sparc: rename __spin_try_lock() and friends
From: Heiko Carstens <[email protected]>
Date: Sat, 29 Aug 2009 12:21:17 +0200
Quoted 10 lines
From: Heiko Carstens <[email protected]>
Rename
__spin_try_trylock()and friends toarch_spin_try_lock()etc.Needed to avoid namespace conflicts when the common code function bodies of
_spin_try_lock()etc. are moved to a header file where the function name would be__spin_try_lock().Cc David S. Miller <[email protected]>Signed-off-by Heiko Carstens <[email protected]>
PATCH 3/8 m68k/asm-offsets: rename pt_regs offset defines
In reply to Heiko CarstensFrom: Heiko Carstens <[email protected]>
In order to be able to use asm-offsets.h in C files the existing namespace conflicts must be solved first. In asm-offsets.h e.g. PT_D0 gets defined which is the offset of the d0 member of the pt_regs structure. However a same define (with a different meaning) exists in asm/ptregs.h.
So rename the defines created with the asm-offset mechanism to PT_OFF_D0 etc. There also already exist a few defines with these names that have the same meaning. So remove the existing defines and use the asm-offset generated ones.
--- arch/m68k/include/asm/entry_mm.h | 4 +--- arch/m68k/include/asm/entry_no.h | 8 ++++---- arch/m68k/include/asm/math-emu.h | 20 ++++++++++---------- arch/m68k/kernel/asm-offsets.c | 26 +++++++++++++------------- arch/m68k/kernel/entry.S | 22 +++++++++++----------- arch/m68k/math-emu/fp_entry.S | 30 +++++++++++++++--------------- 6 files changed, 54 insertions(+), 56 deletions(-)
arch/m68k/include/asm/entry_mm.h +0 -3
@@ -118,9 +119,6 @@ PT_DTRACE_BIT = 2#define STR (X ) STR1(X)#define STR1 (X ) #X -#define PT_OFF_ORIG_D0 0x24 -#define PT_OFF_FORMATVEC 0x32 -#define PT_OFF_SR 0x2C#define SAVE_ALL_INT \ "clrl %%sp@-;"/* stk_adj */ \"pea -1:w;" /* orig d0 = -1 */ \
arch/m68k/kernel/asm-offsets.c +13 -13
@@ -44,20 +44,20 @@ int main(void)DEFINE (TINFO_FLAGS , offsetof(struct thread_info , flags));/* offsets into the pt_regs */ -DEFINE (PT_D0 , offsetof(struct pt_regs , d0)); -DEFINE (PT_ORIG_D0 , offsetof(struct pt_regs , orig_d0)); -DEFINE (PT_D1 , offsetof(struct pt_regs , d1)); -DEFINE (PT_D2 , offsetof(struct pt_regs , d2)); -DEFINE (PT_D3 , offsetof(struct pt_regs , d3)); -DEFINE (PT_D4 , offsetof(struct pt_regs , d4)); -DEFINE (PT_D5 , offsetof(struct pt_regs , d5)); -DEFINE (PT_A0 , offsetof(struct pt_regs , a0)); -DEFINE (PT_A1 , offsetof(struct pt_regs , a1)); -DEFINE (PT_A2 , offsetof(struct pt_regs , a2)); -DEFINE (PT_PC , offsetof(struct pt_regs , pc)); -DEFINE (PT_SR , offsetof(struct pt_regs , sr)); +DEFINE (PT_OFF_D0 , offsetof(struct pt_regs , d0)); +DEFINE (PT_OFF_ORIG_D0 , offsetof(struct pt_regs , orig_d0)); +DEFINE (PT_OFF_D1 , offsetof(struct pt_regs , d1)); +DEFINE (PT_OFF_D2 , offsetof(struct pt_regs , d2)); +DEFINE (PT_OFF_D3 , offsetof(struct pt_regs , d3)); +DEFINE (PT_OFF_D4 , offsetof(struct pt_regs , d4)); +DEFINE (PT_OFF_D5 , offsetof(struct pt_regs , d5)); +DEFINE (PT_OFF_A0 , offsetof(struct pt_regs , a0)); +DEFINE (PT_OFF_A1 , offsetof(struct pt_regs , a1)); +DEFINE (PT_OFF_A2 , offsetof(struct pt_regs , a2)); +DEFINE (PT_OFF_PC , offsetof(struct pt_regs , pc)); +DEFINE (PT_OFF_SR , offsetof(struct pt_regs , sr));/* bitfields are a bit difficult */ -DEFINE (PT_VECTOR , offsetof(struct pt_regs , pc) +4 ); +DEFINE (PT_OFF_FORMATVEC , offsetof(struct pt_regs , pc) +4 );/* offsets into the irq_handler struct */ DEFINE (IRQ_HANDLER , offsetof(struct irq_node , handler));
arch/m68k/kernel/entry.S +11 -11
@@ -77,17 +77,17 @@ ENTRY(ret_from_fork) jra .Lret_from_exception do_trace_entry: - movel #-ENOSYS,%sp@(PT_D0) | needed for strace + movel #-ENOSYS,%sp@(PT_OFF_D0)| needed for strace subql #4,%sp SAVE_SWITCH_STACK jbsr syscall_trace RESTORE_SWITCH_STACK addql #4,%sp - movel %sp@(PT_ORIG_D0),%d0 + movel %sp@(PT_OFF_ORIG_D0),%d0 cmpl #NR_syscalls,%d0 jcs syscall badsys: - movel #-ENOSYS,%sp@(PT_D0) + movel #-ENOSYS,%sp@(PT_OFF_D0) jra ret_from_syscall do_trace_exit:
@@ -103,7 +103,7 @@ ENTRY(ret_from_signal) addql #4,%sp /* on 68040 complete pending writebacks if any */ #ifdef CONFIG_M68040 - bfextu %sp@(PT_VECTOR){#0,#4},%d0 + bfextu %sp@(PT_OFF_FORMATVEC){#0,#4},%d0 subql #7,%d0 | bus error frame ? jbne 1f movel %sp,%sp@-
@@ -127,7 +127,7 @@ ENTRY(system_call) jcc badsys syscall: jbsr @(sys_call_table,%d0:l:4)@(0) - movel %d0,%sp@(PT_D0) | save the return value + movel %d0,%sp@(PT_OFF_D0) | save the return value ret_from_syscall: |oriw #0x0700,%sr movew %curptr@(TASK_INFO+TINFO_FLAGS+2),%d0
@@ -135,7 +135,7 @@ ret_from_syscall: 1: RESTORE_ALL syscall_exit_work: - btst #5,%sp@(PT_SR) | check if returning to kernel + btst #5,%sp@(PT_OFF_SR) | check if returning to kernel bnes 1b | if so, skip resched, signals lslw #1,%d0 jcs do_trace_exit
@@ -148,7 +148,7 @@ syscall_exit_work: ENTRY(ret_from_exception) .Lret_from_exception: - btst #5,%sp@(PT_SR) | check if returning to kernel + btst #5,%sp@(PT_OFF_SR) | check if returning to kernel bnes 1f | if so, skip resched, signals | only allow interrupts when we are really the last one on the | kernel stack, otherwise stack overflow can occur during
@@ -182,7 +182,7 @@ do_signal_return: jbra resume_userspace do_delayed_trace: - bclr #7,%sp@(PT_SR) | clear trace bit in SR + bclr #7,%sp@(PT_OFF_SR) | clear trace bit in SR pea 1 | send SIGTRAP movel %curptr,%sp@- pea LSIGTRAP
@@ -199,7 +199,7 @@ ENTRY(auto_inthandler) GET_CURRENT(%d0) addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | put exception # in d0 - bfextu %sp@(PT_VECTOR){#4,#10},%d0 + bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0 subw #VEC_SPUR,%d0 movel %sp,%sp@-
@@ -216,7 +216,7 @@ ret_from_interrupt: ALIGN ret_from_last_interrupt: moveq #(~ALLOWINT>>8)&0xff,%d0 - andb %sp@(PT_SR),%d0 + andb %sp@(PT_OFF_SR),%d0 jne 2b /* check if we need to do software interrupts */
@@ -232,7 +232,7 @@ ENTRY(user_inthandler) GET_CURRENT(%d0) addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | put exception # in d0 - bfextu %sp@(PT_VECTOR){#4,#10},%d0 + bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0 user_irqvec_fixup = . + 2 subw #VEC_USER,%d0
arch/m68k/math-emu/fp_entry.S +15 -15
@@ -122,17 +122,17 @@ fp_get_data_reg: .long fp_get_d6, fp_get_d7 fp_get_d0: - move.l (PT_D0+8,%sp),%d0 + move.l (PT_OFF_D0+8,%sp),%d0 printf PREGISTER,"{d0->%08x}",1,%d0 rts fp_get_d1: - move.l (PT_D1+8,%sp),%d0 + move.l (PT_OFF_D1+8,%sp),%d0 printf PREGISTER,"{d1->%08x}",1,%d0 rts fp_get_d2: - move.l (PT_D2+8,%sp),%d0 + move.l (PT_OFF_D2+8,%sp),%d0 printf PREGISTER,"{d2->%08x}",1,%d0 rts
@@ -173,35 +173,35 @@ fp_put_data_reg: fp_put_d0: printf PREGISTER,"{d0<-%08x}",1,%d0 - move.l %d0,(PT_D0+8,%sp) + move.l %d0,(PT_OFF_D0+8,%sp) rts fp_put_d1: printf PREGISTER,"{d1<-%08x}",1,%d0 - move.l %d0,(PT_D1+8,%sp) + move.l %d0,(PT_OFF_D1+8,%sp) rts fp_put_d2: printf PREGISTER,"{d2<-%08x}",1,%d0 - move.l %d0,(PT_D2+8,%sp) + move.l %d0,(PT_OFF_D2+8,%sp) rts fp_put_d3: printf PREGISTER,"{d3<-%08x}",1,%d0 | move.l %d0,%d3 - move.l %d0,(PT_D3+8,%sp) + move.l %d0,(PT_OFF_D3+8,%sp) rts fp_put_d4: printf PREGISTER,"{d4<-%08x}",1,%d0 | move.l %d0,%d4 - move.l %d0,(PT_D4+8,%sp) + move.l %d0,(PT_OFF_D4+8,%sp) rts fp_put_d5: printf PREGISTER,"{d5<-%08x}",1,%d0 | move.l %d0,%d5 - move.l %d0,(PT_D5+8,%sp) + move.l %d0,(PT_OFF_D5+8,%sp) rts fp_put_d6:
@@ -225,17 +225,17 @@ fp_get_addr_reg: .long fp_get_a6, fp_get_a7 fp_get_a0: - move.l (PT_A0+8,%sp),%a0 + move.l (PT_OFF_A0+8,%sp),%a0 printf PREGISTER,"{a0->%08x}",1,%a0 rts fp_get_a1: - move.l (PT_A1+8,%sp),%a0 + move.l (PT_OFF_A1+8,%sp),%a0 printf PREGISTER,"{a1->%08x}",1,%a0 rts fp_get_a2: - move.l (PT_A2+8,%sp),%a0 + move.l (PT_OFF_A2+8,%sp),%a0 printf PREGISTER,"{a2->%08x}",1,%a0 rts
@@ -276,17 +276,17 @@ fp_put_addr_reg: fp_put_a0: printf PREGISTER,"{a0<-%08x}",1,%a0 - move.l %a0,(PT_A0+8,%sp) + move.l %a0,(PT_OFF_A0+8,%sp) rts fp_put_a1: printf PREGISTER,"{a1<-%08x}",1,%a0 - move.l %a0,(PT_A1+8,%sp) + move.l %a0,(PT_OFF_A1+8,%sp) rts fp_put_a2: printf PREGISTER,"{a2<-%08x}",1,%a0 - move.l %a0,(PT_A2+8,%sp) + move.l %a0,(PT_OFF_A2+8,%sp) rts fp_put_a3:
arch/m68k/include/asm/entry_no.h +4 -4
@@ -72,8 +72,8 @@ LENOSYS = 38 lea %sp@(-32),%sp /* space for 8 regs */ moveml %d1-%d5/%a0-%a2,%sp@ movel sw_usp,%a0 /* get usp */ - movel %a0@-,%sp@(PT_PC) /* copy exception program counter */ - movel %a0@-,%sp@(PT_FORMATVEC)/* copy exception format/vector/sr */ + movel %a0@-,%sp@(PT_OFF_PC) /* copy exception program counter */ + movel %a0@-,%sp@(PT_OFF_FORMATVEC)/*copy exception format/vector/sr */ bra 7f 6: clrl %sp@- /* stkadj */
@@ -89,8 +89,8 @@ LENOSYS = 38 bnes 8f /* no, skip */ move #0x2700,%sr /* disable intrs */ movel sw_usp,%a0 /* get usp */ - movel %sp@(PT_PC),%a0@- /* copy exception program counter */ - movel %sp@(PT_FORMATVEC),%a0@-/* copy exception format/vector/sr */ + movel %sp@(PT_OFF_PC),%a0@- /* copy exception program counter */ + movel %sp@(PT_OFF_FORMATVEC),%a0@-/*copy exception format/vector/sr */ moveml %sp@,%d1-%d5/%a0-%a2 lea %sp@(32),%sp /* space for 8 regs */ movel %sp@+,%d0
arch/m68k/include/asm/math-emu.h +10 -10
@@ -145,16 +145,16 @@ extern unsigned int fp_debugprint;* these are only used during instruction decoding * where we always know how deep we're on the stack. */ -#define FPS_DO (PT_D0) -#define FPS_D1 (PT_D1) -#define FPS_D2 (PT_D2) -#define FPS_A0 (PT_A0) -#define FPS_A1 (PT_A1) -#define FPS_A2 (PT_A2) -#define FPS_SR (PT_SR) -#define FPS_PC (PT_PC) -#define FPS_EA (PT_PC+6) -#define FPS_PC2 (PT_PC+10) +#define FPS_DO (PT_OFF_D0) +#define FPS_D1 (PT_OFF_D1) +#define FPS_D2 (PT_OFF_D2) +#define FPS_A0 (PT_OFF_A0) +#define FPS_A1 (PT_OFF_A1) +#define FPS_A2 (PT_OFF_A2) +#define FPS_SR (PT_OFF_SR) +#define FPS_PC (PT_OFF_PC) +#define FPS_EA (PT_OFF_PC+6) +#define FPS_PC2 (PT_OFF_PC+10) .macro fp_get_fp_reg lea (FPD_FPREG,FPDATA,%d0.w*4),%a0
PATCH 4/8 m68k/asm-offsets: rename signal defines
In reply to Heiko CarstensFrom: Heiko Carstens <[email protected]>
In order to be able to use asm-offsets.h in C files the existing namespace conflicts must be solved first. In asm-offsets.h there are defines for signal constants, so they can be used in assembler files.
Unfortunately the existing defines use a 1:1 mapping for the macro names which results in name space conflicts if the header file would also be used in C files. So rename the created defines and add an "L" prefix to each one since that has already been done for the SIGTRAP define in entry_mm.
--- arch/m68k/include/asm/entry_mm.h | 1 - arch/m68k/kernel/asm-offsets.c | 8 ++++---- arch/m68k/math-emu/fp_entry.S | 8 ++++---- 3 files changed, 8 insertions(+), 9 deletions(-)
arch/m68k/include/asm/entry_mm.h +0 -1
@@ -46,7 +46,6 @@#define curptr a2 LFLUSH_I_AND_D = 0x00000808 -LSIGTRAP = 5/* process bits for task_struct.ptrace */ PT_TRACESYS_OFF =3
arch/m68k/kernel/asm-offsets.c +4 -4
@@ -84,10 +84,10 @@ int main(void)DEFINE (FONT_DESC_PREF , offsetof(struct font_desc , pref));/* signal defines */ -DEFINE (SIGSEGV ,SIGSEGV ); -DEFINE (SEGV_MAPERR ,SEGV_MAPERR ); -DEFINE (SIGTRAP ,SIGTRAP ); -DEFINE (TRAP_TRACE ,TRAP_TRACE ); +DEFINE (LSIGSEGV ,SIGSEGV ); +DEFINE (LSEGV_MAPERR ,SEGV_MAPERR ); +DEFINE (LSIGTRAP ,SIGTRAP ); +DEFINE (LTRAP_TRACE ,TRAP_TRACE );/* offsets into the custom struct */ DEFINE (CUSTOMBASE , &amiga_custom);
arch/m68k/math-emu/fp_entry.S +4 -4
@@ -85,8 +85,8 @@ fp_err_ua2: fp_err_ua1: addq.l #4,%sp move.l %a0,-(%sp) - pea SEGV_MAPERR - pea SIGSEGV + pea LSEGV_MAPERR + pea LSIGSEGV jsr fpemu_signal add.w #12,%sp jra ret_from_exception
@@ -96,8 +96,8 @@ fp_err_ua1: | it does not really belong here, but... fp_sendtrace060: move.l (FPS_PC,%sp),-(%sp) - pea TRAP_TRACE - pea SIGTRAP + pea LTRAP_TRACE + pea LSIGTRAP jsr fpemu_signal add.w #12,%sp jra ret_from_exception
PATCH 5/8 m68k: calculate thread_info offset with asm offset
In reply to Heiko CarstensFrom: Heiko Carstens <[email protected]>
m68k has the thread_info structure embedded in its task struct. Therefore its not possible to implement current_thread_info() by looking at the stack pointer and do some simple calculations like most other architectures do it.
To return the thread_info pointer for a task two defines are used. This works until the spinlock function bodies get moved into an own header file and CONFIG_SPINLOCK_DEBUG is turned on. That results into this compile error:
In file included from include/linux/spinlock.h:378,
from include/linux/seqlock.h:29,
from include/linux/time.h:8,
from include/linux/timex.h:56,
from include/linux/sched.h:54,
from arch/m68k/kernel/asm-offsets.c:12:include/linux/spinlock_api_smp.h: In function '__spin_unlock_irq':include/linux/spinlock_api_smp.h:371: error: 'current' undeclared (first use in this function) include/linux/spinlock_api_smp.h:371: error: (Each undeclared identifier is reported only once include/linux/spinlock_api_smp.h:371: error: for each function it appears in.)
Including asm/current.h to asm-offsets.c wouldn't help since the definition of struct task is needed. So we end up with ugly header file include dependencies.
To solve this calculate the offset of the thread_info structure into the task struct in asm-offsets.h and use the offset in task_thread_info(). This works just like it does for IA64 as well.
--- arch/m68k/include/asm/thread_info_mm.h | 11 ++++++++++- arch/m68k/kernel/asm-offsets.c | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-)
arch/m68k/include/asm/thread_info_mm.h +10 -1
@@ -1,6 +1,10 @@#ifndef _ASM_M68K_THREAD_INFO_H#define _ASM_M68K_THREAD_INFO_H +#ifndef ASM_OFFSETS_C +#include <asm/asm-offsets.h> +#endif +#include <asm/current.h> #include <asm/types.h> #include <asm/page.h>
@@ -31,7 +35,12 @@ struct thread_info {#define init_thread_info (init_task.thread.info)#define init_stack (init_thread_union.stack) -#define task_thread_info (tsk) (&(tsk)->thread.info) +#ifdef ASM_OFFSETS_C +#define task_thread_info (tsk) ((struct thread_info *) NULL) +#else +#define task_thread_info (tsk) ((struct thread_info *)((char *)tsk+TASK_TINFO)) +#endif +#define task_stack_page (tsk) ((tsk)->stack)#define current_thread_info () task_thread_info(current)
arch/m68k/kernel/asm-offsets.c +5 -0
@@ -8,6 +8,8 @@* #defines from the assembly-language output. */ +#define ASM_OFFSETS_C +#include <linux/stddef.h> #include <linux/sched.h> #include <linux/kernel_stat.h>
@@ -27,6 +29,9 @@ int main(void) DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));DEFINE (TASK_MM , offsetof(struct task_struct , mm));DEFINE (TASK_ACTIVE_MM , offsetof(struct task_struct , active_mm)); +#ifdef CONFIG_MMU + DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info)); +#endif /* offsets into the thread struct */ DEFINE (THREAD_KSP , offsetof(struct thread_struct , ksp));
PATCH 6/8 spinlock: move spinlock function bodies to header file
In reply to Heiko CarstensFrom: Heiko Carstens <[email protected]>
Move spinlock function bodies to header file by creating a static inline version of each variant.
Use the inline version on the out-of-line code. This shouldn't make any difference besides that the spinlock code can now be used to generate inlined spinlock code.
--- include/linux/spinlock.h | 18 +- include/linux/spinlock_api_smp.h | 263 +++++++++++++++++++++++++++++++++++++++ kernel/spinlock.c | 174 ++++--------------------- 3 files changed, 300 insertions(+), 155 deletions(-)
include/linux/spinlock_api_smp.h +263 -0
@@ -60,4 +60,267 @@ void __lockfunc _read_unlock_irqrestore( void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) __releases(lock); +static inline int __spin_trylock (spinlock_t *lock) +{ +preempt_disable (); +if (_raw_spin_trylock (lock)) { +spin_acquire (&lock->dep_map,0 ,1 , _RET_IP_); +return 1 ; + } +preempt_enable (); +return 0 ; +} + +static inline int __read_trylock (rwlock_t *lock) +{ +preempt_disable (); +if (_raw_read_trylock (lock)) { +rwlock_acquire_read (&lock->dep_map,0 ,1 , _RET_IP_); +return 1 ; + } +preempt_enable (); +return 0 ; +} + +static inline int __write_trylock (rwlock_t *lock) +{ +preempt_disable (); +if (_raw_write_trylock (lock)) { +rwlock_acquire (&lock->dep_map,0 ,1 , _RET_IP_); +return 1 ; + } +preempt_enable (); +return 0 ; +} + +/* +* If lockdep is enabled then we use the non-preemption spin-ops +* even on CONFIG_PREEMPT, because lockdep assumes that interrupts are +* not re-enabled during lock-acquire (which the preempt-spin-ops do): +*/ +#if !defined(CONFIG_GENERIC_LOCKBREAK ) || defined(CONFIG_DEBUG_LOCK_ALLOC ) + +static inline void __read_lock (rwlock_t *lock) +{ +preempt_disable (); +rwlock_acquire_read (&lock->dep_map,0 ,0 , _RET_IP_); +LOCK_CONTENDED (lock, _raw_read_trylock, _raw_read_lock); +} + +static inline unsigned long __spin_lock_irqsave (spinlock_t *lock) +{ +unsigned long flags; + +local_irq_save (flags); +preempt_disable (); +spin_acquire (&lock->dep_map,0 ,0 , _RET_IP_); +/* +* On lockdep we dont want the hand-coded irq-enable of +* _raw_spin_lock_flags() code, because lockdep assumes +* that interrupts are not re-enabled during lock-acquire: +*/ +#ifdef CONFIG_LOCKDEP +LOCK_CONTENDED (lock, _raw_spin_trylock, _raw_spin_lock); +#else +_raw_spin_lock_flags (lock, &flags); +#endif +return flags; +} + +static inline void __spin_lock_irq (spinlock_t *lock) +{ +local_irq_disable (); +preempt_disable (); +spin_acquire (&lock->dep_map,0 ,0 , _RET_IP_); +LOCK_CONTENDED (lock, _raw_spin_trylock, _raw_spin_lock); +} + +static inline void __spin_lock_bh (spinlock_t *lock) +{ +local_bh_disable (); +preempt_disable (); +spin_acquire (&lock->dep_map,0 ,0 , _RET_IP_); +LOCK_CONTENDED (lock, _raw_spin_trylock, _raw_spin_lock); +} + +static inline unsigned long __read_lock_irqsave (rwlock_t *lock) +{ +unsigned long flags; + +local_irq_save (flags); +preempt_disable (); +rwlock_acquire_read (&lock->dep_map,0 ,0 , _RET_IP_); +LOCK_CONTENDED_FLAGS (lock, _raw_read_trylock, _raw_read_lock, + _raw_read_lock_flags, &flags); +return flags; +} + +static inline void __read_lock_irq (rwlock_t *lock) +{ +local_irq_disable (); +preempt_disable (); +rwlock_acquire_read (&lock->dep_map,0 ,0 , _RET_IP_); +LOCK_CONTENDED (lock, _raw_read_trylock, _raw_read_lock); +} + +static inline void __read_lock_bh (rwlock_t *lock) +{ +local_bh_disable (); +preempt_disable (); +rwlock_acquire_read (&lock->dep_map,0 ,0 , _RET_IP_); +LOCK_CONTENDED (lock, _raw_read_trylock, _raw_read_lock); +} + +static inline unsigned long __write_lock_irqsave (rwlock_t *lock) +{ +unsigned long flags; + +local_irq_save (flags); +preempt_disable (); +rwlock_acquire (&lock->dep_map,0 ,0 , _RET_IP_); +LOCK_CONTENDED_FLAGS (lock, _raw_write_trylock, _raw_write_lock, + _raw_write_lock_flags, &flags); +return flags; +} + +static inline void __write_lock_irq (rwlock_t *lock) +{ +local_irq_disable (); +preempt_disable (); +rwlock_acquire (&lock->dep_map,0 ,0 , _RET_IP_); +LOCK_CONTENDED (lock, _raw_write_trylock, _raw_write_lock); +} + +static inline void __write_lock_bh (rwlock_t *lock) +{ +local_bh_disable (); +preempt_disable (); +rwlock_acquire (&lock->dep_map,0 ,0 , _RET_IP_); +LOCK_CONTENDED (lock, _raw_write_trylock, _raw_write_lock); +} + +static inline void __spin_lock (spinlock_t *lock) +{ +preempt_disable (); +spin_acquire (&lock->dep_map,0 ,0 , _RET_IP_); +LOCK_CONTENDED (lock, _raw_spin_trylock, _raw_spin_lock); +} + +static inline void __write_lock (rwlock_t *lock) +{ +preempt_disable (); +rwlock_acquire (&lock->dep_map,0 ,0 , _RET_IP_); +LOCK_CONTENDED (lock, _raw_write_trylock, _raw_write_lock); +} + +#endif /* CONFIG_PREEMPT */ + +static inline void __spin_unlock (spinlock_t *lock) +{ +spin_release (&lock->dep_map,1 , _RET_IP_); +_raw_spin_unlock (lock); +preempt_enable (); +} + +static inline void __write_unlock (rwlock_t *lock) +{ +rwlock_release (&lock->dep_map,1 , _RET_IP_); +_raw_write_unlock (lock); +preempt_enable (); +} + +static inline void __read_unlock (rwlock_t *lock) +{ +rwlock_release (&lock->dep_map,1 , _RET_IP_); +_raw_read_unlock (lock); +preempt_enable (); +} + +static inline void __spin_unlock_irqrestore (spinlock_t *lock, +unsigned long flags) +{ +spin_release (&lock->dep_map,1 , _RET_IP_); +_raw_spin_unlock (lock); +local_irq_restore (flags); +preempt_enable (); +} + +static inline void __spin_unlock_irq (spinlock_t *lock) +{ +spin_release (&lock->dep_map,1 , _RET_IP_); +_raw_spin_unlock (lock); +local_irq_enable (); +preempt_enable (); +} + +static inline void __spin_unlock_bh (spinlock_t *lock) +{ +spin_release (&lock->dep_map,1 , _RET_IP_); +_raw_spin_unlock (lock); +preempt_enable_no_resched (); +local_bh_enable_ip ((unsigned long )__builtin_return_address (0 )); +} + +static inline void __read_unlock_irqrestore (rwlock_t *lock,unsigned long flags) +{ +rwlock_release (&lock->dep_map,1 , _RET_IP_); +_raw_read_unlock (lock); +local_irq_restore (flags); +preempt_enable (); +} + +static inline void __read_unlock_irq (rwlock_t *lock) +{ +rwlock_release (&lock->dep_map,1 , _RET_IP_); +_raw_read_unlock (lock); +local_irq_enable (); +preempt_enable (); +} + +static inline void __read_unlock_bh (rwlock_t *lock) +{ +rwlock_release (&lock->dep_map,1 , _RET_IP_); +_raw_read_unlock (lock); +preempt_enable_no_resched (); +local_bh_enable_ip ((unsigned long )__builtin_return_address (0 )); +} + +static inline void __write_unlock_irqrestore (rwlock_t *lock, +unsigned long flags) +{ +rwlock_release (&lock->dep_map,1 , _RET_IP_); +_raw_write_unlock (lock); +local_irq_restore (flags); +preempt_enable (); +} + +static inline void __write_unlock_irq (rwlock_t *lock) +{ +rwlock_release (&lock->dep_map,1 , _RET_IP_); +_raw_write_unlock (lock); +local_irq_enable (); +preempt_enable (); +} + +static inline void __write_unlock_bh (rwlock_t *lock) +{ +rwlock_release (&lock->dep_map,1 , _RET_IP_); +_raw_write_unlock (lock); +preempt_enable_no_resched (); +local_bh_enable_ip ((unsigned long )__builtin_return_address (0 )); +} + +static inline int __spin_trylock_bh (spinlock_t *lock) +{ +local_bh_disable (); +preempt_disable (); +if (_raw_spin_trylock (lock)) { +spin_acquire (&lock->dep_map,0 ,1 , _RET_IP_); +return 1 ; + } +preempt_enable_no_resched (); +local_bh_enable_ip ((unsigned long )__builtin_return_address (0 )); +return 0 ; +} +#endif /* __LINUX_SPINLOCK_API_SMP_H */
include/linux/spinlock.h +9 -9
@@ -143,15 +143,6 @@ static inline void smp_mb__after_lock(vo*/ #define spin_unlock_wait (lock) __raw_spin_unlock_wait(&(lock)->raw_lock) -/* -* Pull the _spin_*()/_read_*()/_write_*() functions/declarations: -*/ -#if defined(CONFIG_SMP ) || defined(CONFIG_DEBUG_SPINLOCK ) -# include <linux/spinlock_api_smp.h> -#else -# include <linux/spinlock_api_up.h> -#endif -#ifdef CONFIG_DEBUG_SPINLOCK extern void _raw_spin_lock (spinlock_t *lock);#define _raw_spin_lock_flags (lock, flags) _raw_spin_lock(lock)
@@ -380,4 +371,13 @@ extern int _atomic_dec_and_lock(atomic_t*/ #define spin_can_lock (lock) (!spin_is_locked(lock)) +/* +* Pull the _spin_*()/_read_*()/_write_*() functions/declarations: +*/ +#if defined(CONFIG_SMP ) || defined(CONFIG_DEBUG_SPINLOCK ) +# include <linux/spinlock_api_smp.h> +#else +# include <linux/spinlock_api_up.h> +#endif +#endif /* __LINUX_SPINLOCK_H */
kernel/spinlock.c +28 -146
318 lines not on this page · raw message
PATCH 7/8 spinlock: allow inlined spinlocks
In reply to Heiko CarstensFrom: Heiko Carstens <[email protected]>
This allows an architecture to specify per lock variant if the locking code should be kept out-of-line or inlined.
If an architecure wants out-of-line locking code no change is needed. To force inlining of e.g. spin_lock() the line
#define __spin_lock_is_small
needs to be added to arch/<whatever>/include/asm/spinlock.h
If CONFIG_DEBUG_SPINLOCK or CONFIG_GENERIC_LOCKBREAK are defined the per architecture defines are (partly) ignored and still out-of-line spinlock code will be generated.
--- include/linux/spinlock_api_smp.h | 119 +++++++++++++++++++++++++++++++++++++++ kernel/spinlock.c | 56 ++++++++++++++++++ 2 files changed, 175 insertions(+)
kernel/spinlock.c +56 -0
@@ -21,23 +21,29 @@#include <linux/debug_locks.h> #include <linux/module.h> +#ifndef _spin_trylock int __lockfunc _spin_trylock(spinlock_t *lock) {return __spin_trylock (lock); }EXPORT_SYMBOL (_spin_trylock); +#endif +#ifndef _read_trylock int __lockfunc _read_trylock(rwlock_t *lock) {return __read_trylock (lock); }EXPORT_SYMBOL (_read_trylock); +#endif +#ifndef _write_trylock int __lockfunc _write_trylock(rwlock_t *lock) {return __write_trylock (lock); }EXPORT_SYMBOL (_write_trylock); +#endif /* * If lockdep is enabled then we use the non-preemption spin-ops
@@ -46,77 +52,101 @@ EXPORT_SYMBOL(_write_trylock);*/ #if !defined(CONFIG_GENERIC_LOCKBREAK ) || defined(CONFIG_DEBUG_LOCK_ALLOC ) +#ifndef _read_lock void __lockfunc _read_lock(rwlock_t *lock) {__read_lock (lock); }EXPORT_SYMBOL (_read_lock); +#endif +#ifndef _spin_lock_irqsaveunsigned long __lockfunc _spin_lock_irqsave (spinlock_t *lock) {return __spin_lock_irqsave (lock); }EXPORT_SYMBOL (_spin_lock_irqsave); +#endif +#ifndef _spin_lock_irq void __lockfunc _spin_lock_irq(spinlock_t *lock) {__spin_lock_irq (lock); }EXPORT_SYMBOL (_spin_lock_irq); +#endif +#ifndef _spin_lock_bh void __lockfunc _spin_lock_bh(spinlock_t *lock) {__spin_lock_bh (lock); }EXPORT_SYMBOL (_spin_lock_bh); +#endif +#ifndef _read_lock_irqsaveunsigned long __lockfunc _read_lock_irqsave (rwlock_t *lock) {return __read_lock_irqsave (lock); }EXPORT_SYMBOL (_read_lock_irqsave); +#endif +#ifndef _read_lock_irq void __lockfunc _read_lock_irq(rwlock_t *lock) {__read_lock_irq (lock); }EXPORT_SYMBOL (_read_lock_irq); +#endif +#ifndef _read_lock_bh void __lockfunc _read_lock_bh(rwlock_t *lock) {__read_lock_bh (lock); }EXPORT_SYMBOL (_read_lock_bh); +#endif +#ifndef _write_lock_irqsaveunsigned long __lockfunc _write_lock_irqsave (rwlock_t *lock) {return __write_lock_irqsave (lock); }EXPORT_SYMBOL (_write_lock_irqsave); +#endif +#ifndef _write_lock_irq void __lockfunc _write_lock_irq(rwlock_t *lock) {__write_lock_irq (lock); }EXPORT_SYMBOL (_write_lock_irq); +#endif +#ifndef _write_lock_bh void __lockfunc _write_lock_bh(rwlock_t *lock) {__write_lock_bh (lock); }EXPORT_SYMBOL (_write_lock_bh); +#endif +#ifndef _spin_lock void __lockfunc _spin_lock(spinlock_t *lock) {__spin_lock (lock); }EXPORT_SYMBOL (_spin_lock); +#endif +#ifndef _write_lock void __lockfunc _write_lock(rwlock_t *lock) {__write_lock (lock); }EXPORT_SYMBOL (_write_lock); +#endif #else /* CONFIG_PREEMPT: */
@@ -242,83 +272,109 @@ EXPORT_SYMBOL(_spin_lock_nest_lock);#endif +#ifndef _spin_unlock void __lockfunc _spin_unlock(spinlock_t *lock) {__spin_unlock (lock); }EXPORT_SYMBOL (_spin_unlock); +#endif +#ifndef _write_unlock void __lockfunc _write_unlock(rwlock_t *lock) {__write_unlock (lock); }EXPORT_SYMBOL (_write_unlock); +#endif +#ifndef _read_unlock void __lockfunc _read_unlock(rwlock_t *lock) {__read_unlock (lock); }EXPORT_SYMBOL (_read_unlock); +#endif +#ifndef _spin_unlock_irqrestore void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) {__spin_unlock_irqrestore (lock, flags); }EXPORT_SYMBOL (_spin_unlock_irqrestore); +#endif +#ifndef _spin_unlock_irq void __lockfunc _spin_unlock_irq(spinlock_t *lock) {__spin_unlock_irq (lock); }EXPORT_SYMBOL (_spin_unlock_irq); +#endif +#ifndef _spin_unlock_bh void __lockfunc _spin_unlock_bh(spinlock_t *lock) {__spin_unlock_bh (lock); }EXPORT_SYMBOL (_spin_unlock_bh); +#endif +#ifndef _read_unlock_irqrestore void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) {__read_unlock_irqrestore (lock, flags); }EXPORT_SYMBOL (_read_unlock_irqrestore); +#endif +#ifndef _read_unlock_irq void __lockfunc _read_unlock_irq(rwlock_t *lock) {__read_unlock_irq (lock); }EXPORT_SYMBOL (_read_unlock_irq); +#endif +#ifndef _read_unlock_bh void __lockfunc _read_unlock_bh(rwlock_t *lock) {__read_unlock_bh (lock); }EXPORT_SYMBOL (_read_unlock_bh); +#endif +#ifndef _write_unlock_irqrestore void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) {__write_unlock_irqrestore (lock, flags); }EXPORT_SYMBOL (_write_unlock_irqrestore); +#endif +#ifndef _write_unlock_irq void __lockfunc _write_unlock_irq(rwlock_t *lock) {__write_unlock_irq (lock); }EXPORT_SYMBOL (_write_unlock_irq); +#endif +#ifndef _write_unlock_bh void __lockfunc _write_unlock_bh(rwlock_t *lock) {__write_unlock_bh (lock); }EXPORT_SYMBOL (_write_unlock_bh); +#endif +#ifndef _spin_trylock_bh int __lockfunc _spin_trylock_bh(spinlock_t *lock) {return __spin_trylock_bh (lock); }EXPORT_SYMBOL (_spin_trylock_bh); +#endif notrace int in_lock_functions(unsigned long addr) {
include/linux/spinlock_api_smp.h +119 -0
125 lines not on this page · raw message
PATCH 8/8 spinlock: inline code for all locking variants on s390
In reply to Heiko CarstensFrom: Heiko Carstens <[email protected]>
--- arch/s390/include/asm/spinlock.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
arch/s390/include/asm/spinlock.h +29 -0
@@ -191,4 +191,33 @@ static inline int __raw_write_trylock(ra#define _raw_read_relax (lock) cpu_relax()#define _raw_write_relax (lock) cpu_relax() +#define __spin_lock_is_small +#define __read_lock_is_small +#define __write_lock_is_small +#define __spin_lock_bh_is_small +#define __read_lock_bh_is_small +#define __write_lock_bh_is_small +#define __spin_lock_irq_is_small +#define __read_lock_irq_is_small +#define __write_lock_irq_is_small +#define __spin_lock_irqsave_is_small +#define __read_lock_irqsave_is_small +#define __write_lock_irqsave_is_small +#define __spin_trylock_is_small +#define __read_trylock_is_small +#define __write_trylock_is_small +#define __spin_trylock_bh_is_small +#define __spin_unlock_is_small +#define __read_unlock_is_small +#define __write_unlock_is_small +#define __spin_unlock_bh_is_small +#define __read_unlock_bh_is_small +#define __write_unlock_bh_is_small +#define __spin_unlock_irq_is_small +#define __read_unlock_irq_is_small +#define __write_unlock_irq_is_small +#define __spin_unlock_irqrestore_is_small +#define __read_unlock_irqrestore_is_small +#define __write_unlock_irqrestore_is_small +#endif /* __ASM_SPINLOCK_H */
Quoted 7 lines · Heiko Carstens
This patch set allows to have inlined spinlocks again.
V2: rewritten from scratch - now also with readable code
V3: removed macro to generate out-of-line spinlock variants since that
would break ctags. As requested by Arnd Bergmann.
Quoted 7 lines
V4: allow architectures to specify for each lock/unlock variant if
it should be kept out-of-line or inlined.V5: simplify ifdefs as pointed out by Linus. Fix architecture compile
breakages caused by this change.Linus, Ingo, do you still have objections?
Ok, this looks pretty clean.
Two small comments. One (small) worry is that the configuration space of this construct:
+#define __spin_lock_is_small
+#define __read_lock_is_small
+#define __write_lock_is_small
+#define __spin_lock_bh_is_small
+#define __read_lock_bh_is_small
+#define __write_lock_bh_is_small
+#define __spin_lock_irq_is_small
+#define __read_lock_irq_is_small
+#define __write_lock_irq_is_small
+#define __spin_lock_irqsave_is_small
+#define __read_lock_irqsave_is_small
+#define __write_lock_irqsave_is_small
+#define __spin_trylock_is_small
+#define __read_trylock_is_small
+#define __write_trylock_is_small
+#define __spin_trylock_bh_is_small
+#define __spin_unlock_is_small
+#define __read_unlock_is_small
+#define __write_unlock_is_small
+#define __spin_unlock_bh_is_small
+#define __read_unlock_bh_is_small
+#define __write_unlock_bh_is_small
+#define __spin_unlock_irq_is_small
+#define __read_unlock_irq_is_small
+#define __write_unlock_irq_is_small
+#define __spin_unlock_irqrestore_is_small
+#define __read_unlock_irqrestore_is_small
+#define __write_unlock_irqrestore_is_small
Is 2^28.
Could we perhaps shape this in a form that makes it 'formally' a manually tuned inlining decision - where we already accept such kind of per function decisions and know how to handle them?
I.e. rename it to something like:
#define __always_inline__write_unlock_irqrestore
That way it fits into our existing forced-inlining attributes (visually and name-space wise), which means the addition of 'inline' or '__forced_inline', or the removal of such attributes.
The closer such a special hack is to already existing principles, the better we'll be able to maintain it as the years progress.
The other comment i have: you dont seem to have preserved the current auto-inlining of spin_lock() we did before, have you? Without that this patchset causes a (small) performance regression on every architectures but s390.
Ingo
Quoted 22 lines · Ingo Molnar
Quoted 6 lines · Heiko Carstens
This patch set allows to have inlined spinlocks again.
V5: simplify ifdefs as pointed out by Linus. Fix architecture compile
breakages caused by this change.Linus, Ingo, do you still have objections?
Ok, this looks pretty clean.
Two small comments. One (small) worry is that the configuration space of this construct:
+#define
__spin_lock_is_small
[...]Is 2^28.
Could we perhaps shape this in a form that makes it 'formally' a manually tuned inlining decision - where we already accept such kind of per function decisions and know how to handle them?
Quoted 7 lines
I.e. rename it to something like:
#define __always_inline__write_unlock_irqrestoreThat way it fits into our existing forced-inlining attributes (visually and name-space wise), which means the addition of 'inline' or '
__forced_inline', or the removal of such attributes.
Ok, I'll wait for more comments and post an updated version.
Quoted 4 lines
The other comment i have: you dont seem to have preserved the current auto-inlining of
spin_lock()we did before, have you? Without that this patchset causes a (small) performance regression on every architectures but s390.
I assume you're talking of spin_unlock() and not spin_lock()?
It still gets inlined (spinlock.h):
/*
* We inline the unlock functions in the nondebug case:
*/
#if defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) || \
!defined(CONFIG_SMP)
# define spin_unlock(lock) _spin_unlock(lock)
[...]
#else
# define spin_unlock(lock) \
do {__raw_spin_unlock(&(lock)->raw_lock); __release(lock); } while (0)
[...]Or in other words, specifying __spin_lock_is_small causes only that the out-of-line variant doesn't get generated anymore.
It gets inlined regardless (if config options allow).
Now this could be simplified/cleanup by doing something like this:
/*
* We inline the unlock functions in the nondebug case:
*/
#if defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) || \
!defined(CONFIG_SMP)
# define spin_unlock(lock) _spin_unlock(lock)
[...]
#else
# define spin_unlock(lock) \
do {__raw_spin_unlock(&(lock)->raw_lock); __release(lock); } while (0)
[...]However it sucks a bit that we have two different ways to force inlining. So we could and probably should simplify this. The patch below (untested) would do that:
--- include/linux/spinlock.h | 46 +++++---------------------------------- include/linux/spinlock_api_smp.h | 12 ++++++++++ 2 files changed, 18 insertions(+), 40 deletions(-)
include/linux/spinlock.h +6 -40
@@ -259,50 +259,16 @@ static inline void smp_mb__after_lock(vo#define spin_lock_irq (lock) _spin_lock_irq(lock)#define spin_lock_bh (lock) _spin_lock_bh(lock) -#define read_lock_irq (lock) _read_lock_irq(lock)#define read_lock_bh (lock) _read_lock_bh(lock) -#define write_lock_irq (lock) _write_lock_irq(lock)#define write_lock_bh (lock) _write_lock_bh(lock) - -/* -* We inline the unlock functions in the nondebug case: -*/ -#if defined(CONFIG_DEBUG_SPINLOCK ) || defined(CONFIG_PREEMPT ) || \ - !defined(CONFIG_SMP ) -# define spin_unlock (lock) _spin_unlock(lock) -# define read_unlock (lock) _read_unlock(lock) -# define write_unlock (lock) _write_unlock(lock) -# define spin_unlock_irq (lock) _spin_unlock_irq(lock) -# define read_unlock_irq (lock) _read_unlock_irq(lock) -# define write_unlock_irq (lock) _write_unlock_irq(lock) -#else -# define spin_unlock (lock) \ - do {__raw_spin_unlock(&(lock)->raw_lock); __release(lock); } while (0) -# define read_unlock (lock) \ - do {__raw_read_unlock(&(lock)->raw_lock); __release(lock); } while (0) -# define write_unlock (lock) \ - do {__raw_write_unlock(&(lock)->raw_lock); __release(lock); } while (0) -# define spin_unlock_irq (lock) \ -do { \ - __raw_spin_unlock(&(lock)->raw_lock); \ - __release(lock); \ - local_irq_enable(); \ -} while (0) -# define read_unlock_irq (lock) \ -do { \ - __raw_read_unlock(&(lock)->raw_lock); \ - __release(lock); \ - local_irq_enable(); \ -} while (0) -# define write_unlock_irq (lock) \ -do { \ - __raw_write_unlock(&(lock)->raw_lock); \ - __release(lock); \ - local_irq_enable(); \ -} while (0) -#endif +#define spin_unlock (lock) _spin_unlock(lock) +#define read_unlock (lock) _read_unlock(lock) +#define write_unlock (lock) _write_unlock(lock) +#define spin_unlock_irq (lock) _spin_unlock_irq(lock) +#define read_unlock_irq (lock) _read_unlock_irq(lock) +#define write_unlock_irq (lock) _write_unlock_irq(lock)#define spin_unlock_irqrestore (lock, flags) \ do { \
include/linux/spinlock_api_smp.h +12 -0
@@ -60,6 +60,18 @@ void __lockfunc _read_unlock_irqrestore( void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) __releases(lock); +/* +* We inline the unlock functions in the nondebug case: +*/ +#if !defined(CONFIG_DEBUG_SPINLOCK ) && !defined(CONFIG_PREEMPT ) +#define __spin_unlock_is_small +#define __read_unlock_is_small +#define __write_unlock_is_small +#define __spin_unlock_irq_is_small +#define __read_unlock_irq_is_small +#define __write_unlock_irq_is_small +#endif +#ifndef CONFIG_DEBUG_SPINLOCK #ifndef CONFIG_GENERIC_LOCKBREAK
Quoted 1 line · Heiko Carstens
I assume you're talking of
spin_unlock()and notspin_lock()?
yeah.
Quoted 32 lines
It still gets inlined (
spinlock.h):/*
* We inline the unlock functions in the nondebug case:
*/
#ifdefined(CONFIG_DEBUG_SPINLOCK)||defined(CONFIG_PREEMPT)|| \
!defined(CONFIG_SMP)# define spin_unlock(lock) _spin_unlock(lock) [...] #else # define spin_unlock(lock) \ do {__raw_spin_unlock(&(lock)->raw_lock); __release(lock); } while (0) [...]Or in other words, specifying
__spin_lock_is_smallcauses only that the out-of-line variant doesn't get generated anymore. It gets inlined regardless (if config options allow).Now this could be simplified/cleanup by doing something like this:
/*
* We inline the unlock functions in the nondebug case:
*/
#ifdefined(CONFIG_DEBUG_SPINLOCK)||defined(CONFIG_PREEMPT)|| \
!defined(CONFIG_SMP)# define spin_unlock(lock) _spin_unlock(lock) [...] #else # define spin_unlock(lock) \ do {__raw_spin_unlock(&(lock)->raw_lock); __release(lock); } while (0) [...]
Quoted 8 lines
However it sucks a bit that we have two different ways to force inlining. So we could and probably should simplify this. The patch below (untested) would do that:
--- include/linux/spinlock.h | 46 +++++---------------------------------- include/linux/spinlock_api_smp.h | 12 ++++++++++ 2 files changed, 18 insertions(+), 40 deletions(-)
Yes, that's exactly what i was thinking of. That way your patchset becomes a cleanup as well, not just a 'touch a lot of dangerous code' excercise in masochism ;-)
A third question would be, now that we have this flexible method to inline/uninline locking APIs, mind checking say a 64-bit x86 defconfig and see whether that generic set of inline/noinline decisions actually results in the smallest possible kernel image size?
I.e. we could use this opportunity to re-tune the generic defaults. (and thus your patch-set would become an improvement as well.)
Ingo
Quoted 8 lines · Ingo Molnar
A third question would be, now that we have this flexible method to inline/uninline locking APIs, mind checking say a 64-bit x86 defconfig and see whether that generic set of inline/noinline decisions actually results in the smallest possible kernel image size?
I.e. we could use this opportunity to re-tune the generic defaults. (and thus your patch-set would become an improvement as well.)
Considering the large x86 user base I have no doubts that you will easily find volunteers who will be happy to do this :)
Quoted 8 lines · Heiko Carstens
Quoted 6 lines · Ingo Molnar
A third question would be, now that we have this flexible method to inline/uninline locking APIs, mind checking say a 64-bit x86 defconfig and see whether that generic set of inline/noinline decisions actually results in the smallest possible kernel image size?
Quoted 6 lines
Quoted 3 lines
I.e. we could use this opportunity to re-tune the generic defaults. (and thus your patch-set would become an improvement as well.)
Considering the large x86 user base I have no doubts that you will easily find volunteers who will be happy to do this :)
Hey, you are turning my own argument against me - that's not fair ;-)
Anyway, your latest bits make testing of it rather straightforward for anyone interested in fine-tuning the defaults (28 kernel builds ought to settle the issue), and the current inlining rules should be rather close to the optimal solution already.
Ingo