Autor komentarzy: Grzegorz Całkowski (gc)
/* * linux/kernel/softirq.c * * Copyright (C) 1992 Linus Torvalds * * do_bottom_half() runs at normal kernel priority: all interrupts * enabled. do_bottom_half() is atomic with respect to itself: a * bottom_half handler need not be re-entrant. */ #include <linux/ptrace.h> #include <linux/errno.h> #include <linux/kernel_stat.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/mm.h> #include <asm/system.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/bitops.h>
Zmienna intr_count - licznik "zagłębień". Jest zwiększany o 1 przy każdym wejściu do procedury obsługi przerwania sprzętowego (patrz makro BUILD_IRQ w pliku include/asm/irq.h) i przed każdym wywołaniem do_bottom_half() oraz zmniejszany o 1 po wyjściu.
unsigned long intr_count = 0;
Tablica liczników włączeń/wyłączeń poszczególnych "bottom halves". Wykorzystywane przez enable_bh(), disable_bh().
int bh_mask_count[32];
Maska aktywnych "bottom halves".
unsigned long bh_active = 0;
Maska zainicjalizowanych "bottom halves".
unsigned long bh_mask = 0;
Tablica procedur (funkcji) obsługi poszczególnych "bottom halves". Patrz linux/interrupt.h.
void (*bh_base[32])(void);
Funkcja wywołująca procedury obsługi dla aktywnych.
asmlinkage void do_bottom_half(void) { unsigned long active; unsigned long mask, left; void (**bh)(void);
Włącz przerwania. Jest to, po pierwsze, bezpieczne - mamy gwarancję, że nie znajdziemy się tu ponownie (patrz arch/i386/kernel/entry.S). Po drugie, przypomnę, ideą "bottom half" jest wykonanie czasochłonych operacji związanych z przerwaniami sprzętowymi poza procedurami ich obsługi.
sti(); bh = bh_base;
Iteracja po kolejnych bitach maski. Zwracam uwagę na dodawanie zamiast przesuwania (autor tej funkcji należy zapewne do starej generacji koderów z czasów, gdy dodanie rejestru do rejestru było szybsze niż przesunięcie o jeden bit w lewo ;-).
active = bh_active & bh_mask; for (mask = 1, left = ~0 ; left & active ; bh++,mask += mask,left += left) { if (mask & active) { void (*fn)(void); bh_active &= ~mask; fn = *bh; if (!fn) goto bad_bh; fn(); } } return; bad_bh: printk ("irq.c:bad bottom half entry %08lx\n", mask); }
(gc)