The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/Documentation/cli-sti-removal.txt

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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         DEFINE_SPINLOCK(driver_lock);
   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 

Cache object: a110dbe7ed58954be242842ee29399be


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.