diff options
| author | Kyle McMartin <kyle@parisc-linux.org> | 2006-03-28 04:56:11 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-28 12:16:01 -0500 |
| commit | f5f5370da4b3128b7dfd944b4fcbb5c7b6887348 (patch) | |
| tree | 45a00ae5b234648083bad84db213da3b8220b679 /include/asm-generic | |
| parent | 4f3a36a7d0eb420471506fcd46ee46f4b5cd4ebc (diff) | |
[PATCH] Decrapify asm-generic/local.h
Now that Christoph Lameter's atomic_long_t support is merged in mainline,
might as well convert asm-generic/local.h to use it, so the same code can
be used for both sizes of 32 and 64-bit unsigned longs.
akpm sayeth:
Q:
Is there any particular reason why these routines weren't simply
implemented with local_save/restore_flags, if they are only meant to
guarantee atomicity to the local cpu? I'm sure on most platforms this
would be more efficient than using an atomic...
A:
The whole _point_ of local_t is to avoid local_irq_disable(). It's
designed to exploit the fact that many CPUs can do incs and decs in a way
which is atomic wrt local interrupts, but not atomic wrt SMP.
But this patch makes sense, because asm-generic/local.h is just a fallback
implementation for architectures which either cannot perform these
local-irq-atomic operations, or its maintainers haven't yet got around to
implementing them.
We need more work done on local_t in the 2.6.17 timeframe - they're defined as
unsigned long, but some architectures implement them as signed long.
Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
Cc: Benjamin LaHaise <bcrl@kvack.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include/asm-generic')
| -rw-r--r-- | include/asm-generic/local.h | 80 |
1 files changed, 9 insertions, 71 deletions
diff --git a/include/asm-generic/local.h b/include/asm-generic/local.h index 16fc00360f75..de4614840c2c 100644 --- a/include/asm-generic/local.h +++ b/include/asm-generic/local.h | |||
| @@ -4,28 +4,28 @@ | |||
| 4 | #include <linux/config.h> | 4 | #include <linux/config.h> |
| 5 | #include <linux/percpu.h> | 5 | #include <linux/percpu.h> |
| 6 | #include <linux/hardirq.h> | 6 | #include <linux/hardirq.h> |
| 7 | #include <asm/atomic.h> | ||
| 7 | #include <asm/types.h> | 8 | #include <asm/types.h> |
| 8 | 9 | ||
| 9 | /* An unsigned long type for operations which are atomic for a single | 10 | /* An unsigned long type for operations which are atomic for a single |
| 10 | * CPU. Usually used in combination with per-cpu variables. */ | 11 | * CPU. Usually used in combination with per-cpu variables. */ |
| 11 | 12 | ||
| 12 | #if BITS_PER_LONG == 32 | ||
| 13 | /* Implement in terms of atomics. */ | 13 | /* Implement in terms of atomics. */ |
| 14 | 14 | ||
| 15 | /* Don't use typedef: don't want them to be mixed with atomic_t's. */ | 15 | /* Don't use typedef: don't want them to be mixed with atomic_t's. */ |
| 16 | typedef struct | 16 | typedef struct |
| 17 | { | 17 | { |
| 18 | atomic_t a; | 18 | atomic_long_t a; |
| 19 | } local_t; | 19 | } local_t; |
| 20 | 20 | ||
| 21 | #define LOCAL_INIT(i) { ATOMIC_INIT(i) } | 21 | #define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) } |
| 22 | 22 | ||
| 23 | #define local_read(l) ((unsigned long)atomic_read(&(l)->a)) | 23 | #define local_read(l) ((unsigned long)atomic_long_read(&(l)->a)) |
| 24 | #define local_set(l,i) atomic_set((&(l)->a),(i)) | 24 | #define local_set(l,i) atomic_long_set((&(l)->a),(i)) |
| 25 | #define local_inc(l) atomic_inc(&(l)->a) | 25 | #define local_inc(l) atomic_long_inc(&(l)->a) |
| 26 | #define local_dec(l) atomic_dec(&(l)->a) | 26 | #define local_dec(l) atomic_long_dec(&(l)->a) |
| 27 | #define local_add(i,l) atomic_add((i),(&(l)->a)) | 27 | #define local_add(i,l) atomic_long_add((i),(&(l)->a)) |
| 28 | #define local_sub(i,l) atomic_sub((i),(&(l)->a)) | 28 | #define local_sub(i,l) atomic_long_sub((i),(&(l)->a)) |
| 29 | 29 | ||
| 30 | /* Non-atomic variants, ie. preemption disabled and won't be touched | 30 | /* Non-atomic variants, ie. preemption disabled and won't be touched |
| 31 | * in interrupt, etc. Some archs can optimize this case well. */ | 31 | * in interrupt, etc. Some archs can optimize this case well. */ |
| @@ -34,68 +34,6 @@ typedef struct | |||
| 34 | #define __local_add(i,l) local_set((l), local_read(l) + (i)) | 34 | #define __local_add(i,l) local_set((l), local_read(l) + (i)) |
| 35 | #define __local_sub(i,l) local_set((l), local_read(l) - (i)) | 35 | #define __local_sub(i,l) local_set((l), local_read(l) - (i)) |
| 36 | 36 | ||
| 37 | #else /* ... can't use atomics. */ | ||
| 38 | /* Implement in terms of three variables. | ||
| 39 | Another option would be to use local_irq_save/restore. */ | ||
| 40 | |||
| 41 | typedef struct | ||
| 42 | { | ||
| 43 | /* 0 = in hardirq, 1 = in softirq, 2 = usermode. */ | ||
| 44 | unsigned long v[3]; | ||
| 45 | } local_t; | ||
| 46 | |||
| 47 | #define _LOCAL_VAR(l) ((l)->v[!in_interrupt() + !in_irq()]) | ||
| 48 | |||
| 49 | #define LOCAL_INIT(i) { { (i), 0, 0 } } | ||
| 50 | |||
| 51 | static inline unsigned long local_read(local_t *l) | ||
| 52 | { | ||
| 53 | return l->v[0] + l->v[1] + l->v[2]; | ||
| 54 | } | ||
| 55 | |||
| 56 | static inline void local_set(local_t *l, unsigned long v) | ||
| 57 | { | ||
| 58 | l->v[0] = v; | ||
| 59 | l->v[1] = l->v[2] = 0; | ||
| 60 | } | ||
| 61 | |||
| 62 | static inline void local_inc(local_t *l) | ||
| 63 | { | ||
| 64 | preempt_disable(); | ||
| 65 | _LOCAL_VAR(l)++; | ||
| 66 | preempt_enable(); | ||
| 67 | } | ||
| 68 | |||
| 69 | static inline void local_dec(local_t *l) | ||
| 70 | { | ||
| 71 | preempt_disable(); | ||
| 72 | _LOCAL_VAR(l)--; | ||
| 73 | preempt_enable(); | ||
| 74 | } | ||
| 75 | |||
| 76 | static inline void local_add(unsigned long v, local_t *l) | ||
| 77 | { | ||
| 78 | preempt_disable(); | ||
| 79 | _LOCAL_VAR(l) += v; | ||
| 80 | preempt_enable(); | ||
| 81 | } | ||
| 82 | |||
| 83 | static inline void local_sub(unsigned long v, local_t *l) | ||
| 84 | { | ||
| 85 | preempt_disable(); | ||
| 86 | _LOCAL_VAR(l) -= v; | ||
| 87 | preempt_enable(); | ||
| 88 | } | ||
| 89 | |||
| 90 | /* Non-atomic variants, ie. preemption disabled and won't be touched | ||
| 91 | * in interrupt, etc. Some archs can optimize this case well. */ | ||
| 92 | #define __local_inc(l) ((l)->v[0]++) | ||
| 93 | #define __local_dec(l) ((l)->v[0]--) | ||
| 94 | #define __local_add(i,l) ((l)->v[0] += (i)) | ||
| 95 | #define __local_sub(i,l) ((l)->v[0] -= (i)) | ||
| 96 | |||
| 97 | #endif /* Non-atomic implementation */ | ||
| 98 | |||
| 99 | /* Use these for per-cpu local_t variables: on some archs they are | 37 | /* Use these for per-cpu local_t variables: on some archs they are |
| 100 | * much more efficient than these naive implementations. Note they take | 38 | * much more efficient than these naive implementations. Note they take |
| 101 | * a variable (eg. mystruct.foo), not an address. | 39 | * a variable (eg. mystruct.foo), not an address. |
