Contents of /alx-src/tags/kernel26-2.6.12-alx-r9/Documentation/cli-sti-removal.txt
Parent Directory | Revision Log
Revision 630 -
(show annotations)
(download)
Wed Mar 4 11:03:09 2009 UTC (15 years, 6 months ago) by niro
File MIME type: text/plain
File size: 4003 byte(s)
Wed Mar 4 11:03:09 2009 UTC (15 years, 6 months ago) by niro
File MIME type: text/plain
File size: 4003 byte(s)
Tag kernel26-2.6.12-alx-r9
1 | |
2 | #### cli()/sti() removal guide, started by Ingo Molnar <mingo@redhat.com> |
3 | |
4 | |
5 | as of 2.5.28, five popular macros have been removed on SMP, and |
6 | are being phased out on UP: |
7 | |
8 | cli(), sti(), save_flags(flags), save_flags_cli(flags), restore_flags(flags) |
9 | |
10 | until now it was possible to protect driver code against interrupt |
11 | handlers via a cli(), but from now on other, more lightweight methods |
12 | have to be used for synchronization, such as spinlocks or semaphores. |
13 | |
14 | for example, driver code that used to do something like: |
15 | |
16 | struct driver_data; |
17 | |
18 | irq_handler (...) |
19 | { |
20 | .... |
21 | driver_data.finish = 1; |
22 | driver_data.new_work = 0; |
23 | .... |
24 | } |
25 | |
26 | ... |
27 | |
28 | ioctl_func (...) |
29 | { |
30 | ... |
31 | cli(); |
32 | ... |
33 | driver_data.finish = 0; |
34 | driver_data.new_work = 2; |
35 | ... |
36 | sti(); |
37 | ... |
38 | } |
39 | |
40 | was SMP-correct because the cli() function ensured that no |
41 | interrupt handler (amongst them the above irq_handler()) function |
42 | would execute while the cli()-ed section is executing. |
43 | |
44 | but from now on a more direct method of locking has to be used: |
45 | |
46 | spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; |
47 | struct driver_data; |
48 | |
49 | irq_handler (...) |
50 | { |
51 | unsigned long flags; |
52 | .... |
53 | spin_lock_irqsave(&driver_lock, flags); |
54 | .... |
55 | driver_data.finish = 1; |
56 | driver_data.new_work = 0; |
57 | .... |
58 | spin_unlock_irqrestore(&driver_lock, flags); |
59 | .... |
60 | } |
61 | |
62 | ... |
63 | |
64 | ioctl_func (...) |
65 | { |
66 | ... |
67 | spin_lock_irq(&driver_lock); |
68 | ... |
69 | driver_data.finish = 0; |
70 | driver_data.new_work = 2; |
71 | ... |
72 | spin_unlock_irq(&driver_lock); |
73 | ... |
74 | } |
75 | |
76 | the above code has a number of advantages: |
77 | |
78 | - the locking relation is easier to understand - actual lock usage |
79 | pinpoints the critical sections. cli() usage is too opaque. |
80 | Easier to understand means it's easier to debug. |
81 | |
82 | - it's faster, because spinlocks are faster to acquire than the |
83 | potentially heavily-used IRQ lock. Furthermore, your driver does |
84 | not have to wait eg. for a big heavy SCSI interrupt to finish, |
85 | because the driver_lock spinlock is only used by your driver. |
86 | cli() on the other hand was used by many drivers, and extended |
87 | the critical section to the whole IRQ handler function - creating |
88 | serious lock contention. |
89 | |
90 | |
91 | to make the transition easier, we've still kept the cli(), sti(), |
92 | save_flags(), save_flags_cli() and restore_flags() macros defined |
93 | on UP systems - but their usage will be phased out until 2.6 is |
94 | released. |
95 | |
96 | drivers that want to disable local interrupts (interrupts on the |
97 | current CPU), can use the following five macros: |
98 | |
99 | local_irq_disable(), local_irq_enable(), local_save_flags(flags), |
100 | local_irq_save(flags), local_irq_restore(flags) |
101 | |
102 | but beware, their meaning and semantics are much simpler, far from |
103 | that of the old cli(), sti(), save_flags(flags) and restore_flags(flags) |
104 | SMP meaning: |
105 | |
106 | local_irq_disable() => turn local IRQs off |
107 | |
108 | local_irq_enable() => turn local IRQs on |
109 | |
110 | local_save_flags(flags) => save the current IRQ state into flags. The |
111 | state can be on or off. (on some |
112 | architectures there's even more bits in it.) |
113 | |
114 | local_irq_save(flags) => save the current IRQ state into flags and |
115 | disable interrupts. |
116 | |
117 | local_irq_restore(flags) => restore the IRQ state from flags. |
118 | |
119 | (local_irq_save can save both irqs on and irqs off state, and |
120 | local_irq_restore can restore into both irqs on and irqs off state.) |
121 | |
122 | another related change is that synchronize_irq() now takes a parameter: |
123 | synchronize_irq(irq). This change too has the purpose of making SMP |
124 | synchronization more lightweight - this way you can wait for your own |
125 | interrupt handler to finish, no need to wait for other IRQ sources. |
126 | |
127 | |
128 | why were these changes done? The main reason was the architectural burden |
129 | of maintaining the cli()/sti() interface - it became a real problem. The |
130 | new interrupt system is much more streamlined, easier to understand, debug, |
131 | and it's also a bit faster - the same happened to it that will happen to |
132 | cli()/sti() using drivers once they convert to spinlocks :-) |
133 |