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/local.h | |
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/local.h')
-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. |