ÖжϷþÎñ³ÌÐòÍùÍù¶¼ÊÇÔÚCPU¹ØÖжϵÄÌõ¼þÏÂÖ´Ðеģ¬ÒÔ±ÜÃâÖжÏǶÌ׶øʹ¿ØÖƸ´ÔÓ»¯¡£µ«ÊÇCPU¹ØÖжϵÄʱ¼ä²»ÄÜÌ«³¤£¬·ñÔòÈÝÒ׶ªÊ§ÖжÏÐźš£Îª´Ë£¬Linux½«ÖжϷþÎñ³ÌÐòÒ»·ÖΪ¶þ£¬¸÷³Æ×÷¡°Top Half¡±ºÍ¡°Bottom Half¡±¡£Ç°Õßͨ³£¶Ôʱ¼äÒªÇó½ÏΪÑϸñ£¬±ØÐëÔÚÖжÏÇëÇó·¢ÉúºóÁ¢¼´»òÖÁÉÙÔÚÒ»¶¨µÄʱ¼äÏÞÖÆÄÚÍê³É¡£Òò´ËΪÁ˱£Ö¤ÕâÖÖ´¦ÀíÄÜÔ×ÓµØÍê³É£¬Top Halfͨ³£ÊÇÔÚCPU¹ØÖжϵÄÌõ¼þÏÂÖ´Ðеġ£¾ßÌåµØ˵£¬Top HalfµÄ·¶Î§°üÀ¨£º´ÓÔÚIDTÖеǼǵÄÖжÏÈë¿Úº¯ÊýÒ»Ö±µ½Çý¶¯³ÌÐò×¢²áÔÚÖжϷþÎñ¶ÓÁÐÖеÄISR¡£¶øBottom HalfÔòÊÇTop Half¸ù¾ÝÐèÒªÀ´µ÷¶ÈÖ´Ðеģ¬ÕâЩ²Ù×÷ÔÊÐíÑÓ³Ùµ½ÉÔºóÖ´ÐУ¬ËüµÄʱ¼äÒªÇó²¢²»Ñϸñ£¬Òò´ËËüͨ³£ÊÇÔÚCPU¿ªÖжϵÄÌõ¼þÏÂÖ´Ðеġ£
µ«ÊÇ£¬LinuxµÄÕâÖÖBottom Half£¨ÒÔϼò³ÆBH£©»úÖÆÓÐÁ½¸öȱµã£¬Ò²¼´£º£¨1£©ÔÚÈÎÒâһʱ¿Ì£¬ÏµÍ³Ö»ÄÜÓÐÒ»¸öCPU¿ÉÒÔÖ´ÐÐBottom Half´úÂ룬ÒÔ·ÀÖ¹Á½¸ö»ò¶à¸öCPUͬʱÀ´Ö´ÐÐBottom Halfº¯Êý¶øÏ໥¸ÉÈÅ¡£Òò´ËBH´úÂëµÄÖ´ÐÐÊÇÑϸñ¡°´®Ðл¯¡±µÄ¡££¨2£©BHº¯Êý²»ÔÊÐíǶÌס£
ÕâÁ½¸öȱµãÔÚµ¥CPUϵͳÖÐÊÇÎ޹ؽôÒªµÄ£¬µ«ÔÚSMPϵͳÖÐÈ´ÊǷdz£ÖÂÃüµÄ¡£ÒòΪBH»úÖƵÄÑϸñ´®Ðл¯Ö´ÐÐÏÔȻûÓгä·ÖÀûÓÃSMPϵͳµÄ¶àCPUÌص㡣Ϊ´Ë£¬Linux2.4ÄÚºËÔÚBH»úÖƵĻù´¡ÉϽøÐÐÁËÀ©Õ¹£¬Õâ¾ÍÊÇËùνµÄ¡°ÈíÖжÏÇëÇó¡±£¨softirq£©»úÖÆ¡£
6£®1 ÈíÖжÏÇëÇó»úÖÆ
LinuxµÄsoftirq»úÖÆÊÇÓëSMP½ôÃܲ»¿É·ÖµÄ¡£Îª´Ë£¬Õû¸ösoftirq»úÖƵÄÉè¼ÆÓëʵÏÖÖÐ×Ôʼ×ÔÖÕ¶¼¹á³¹ÁËÒ»¸ö˼Ï룺¡°Ë´¥·¢£¬ËÖ´ÐС±£¨Who marks£¬Who runs£©£¬Ò²¼´´¥·¢ÈíÖжϵÄÄǸöCPU¸ºÔðÖ´ÐÐËüËù´¥·¢µÄÈíÖжϣ¬¶øÇÒÿ¸öCPU¶¼ÓÉËü×Ô¼ºµÄÈíÖжϴ¥·¢Óë¿ØÖÆ»úÖÆ¡£Õâ¸öÉè¼Æ˼ÏëҲʹµÃsoftirq»úÖƳä·ÖÀûÓÃÁËSMPϵͳµÄÐÔÄܺÍÌص㡣
6£®1£®1 ÈíÖжÏÃèÊö·û
LinuxÔÚinclude/linux/interrupt.hÍ·ÎļþÖж¨ÒåÁËÊý¾Ý½á¹¹softirq_action£¬À´ÃèÊöÒ»¸öÈíÖжÏÇëÇó£¬ÈçÏÂËùʾ£º
/* softirq mask and active fields moved to irq_cpustat_t in
* asm/hardirq.h to get better cache usage. KAO
*/
struct softirq_action
{
void (*action)(struct softirq_action *);
void *data;
};
ÆäÖУ¬º¯ÊýÖ¸ÕëactionÖ¸ÏòÈíÖжÏÇëÇóµÄ·þÎñº¯Êý£¬¶øÖ¸ÕëdataÔòÖ¸ÏòÓÉ·þÎñº¯Êý×ÔÐнâÊ͵ÄÊý¾Ý¡£
»ùÓÚÉÏÊöÈíÖжÏÃèÊö·û£¬LinuxÔÚkernel/softirq.cÎļþÖж¨ÒåÁËÒ»¸öÈ«¾ÖµÄsoftirq_vec[32]Êý×飺
static struct softirq_action softirq_vec[32] __cacheline_aligned;
ÔÚÕâÀïϵͳһ¹²¶¨ÒåÁË32¸öÈíÖжÏÇëÇóÃèÊö·û¡£ÈíÖжÏÏòÁ¿i£¨0¡Üi¡Ü31£©Ëù¶ÔÓ¦µÄÈíÖжÏÇëÇóÃèÊö·û¾ÍÊÇsoftirq_vec£Ûi£Ý¡£Õâ¸öÊý×éÊǸöϵͳȫ¾ÖÊý×飬Ҳ¼´Ëü±»ËùÓеÄCPUËù¹²Ïí¡£ÕâÀïÐèҪעÒâµÄÒ»µãÊÇ£ºÃ¿¸öCPUËäÈ»¶¼ÓÉËü×Ô¼ºµÄ´¥·¢ºÍ¿ØÖÆ»úÖÆ£¬²¢ÇÒÖ»Ö´ÐÐËû×Ô¼ºËù´¥·¢µÄÈíÖжÏÇëÇ󣬵«ÊǸ÷¸öCPUËùÖ´ÐеÄÈíÖжϷþÎñÀý³ÌÈ´ÊÇÏàͬµÄ£¬Ò²¼´¶¼ÊÇÖ´ÐÐsoftirq_vec£Û£ÝÊý×éÖж¨ÒåµÄÈíÖжϷþÎñº¯Êý¡£
6£®1£®2 ÈíÖжϴ¥·¢»úÖÆ
ҪʵÏÖ¡°Ë´¥·¢£¬ËÖ´ÐС±µÄ˼Ï룬¾Í±ØÐëΪÿ¸öCPU¶¼¶¨ÒåËü×Ô¼ºµÄ´¥·¢ºÍ¿ØÖƱäÁ¿¡£Îª´Ë£¬LinuxÔÚinclude/asm-i386/hardirq.hÍ·ÎļþÖж¨ÒåÁËÊý¾Ý½á¹¹irq_cpustat_tÀ´ÃèÊöÒ»¸öCPUµÄÖжÏͳ¼ÆÐÅÏ¢£¬ÆäÖоÍÓÐÓÃÓÚ´¥·¢ºÍ¿ØÖÆÈíÖжϵijÉÔ±±äÁ¿¡£Êý¾Ý½á¹¹irq_cpustat_tµÄ¶¨ÒåÈçÏ£º
/* entry.S is sensitive to the offsets of these fields */
typedef struct {
unsigned int __softirq_active;
unsigned int __softirq_mask;
unsigned int __local_irq_count;
unsigned int __local_bh_count;
unsigned int __syscall_count;
unsigned int __nmi_count; /* arch dependent */
} ____cacheline_aligned irq_cpustat_t;
½á¹¹ÖÐÿһ¸ö³ÉÔ±¶¼ÊÇÒ»¸ö32λµÄÎÞ·ûºÅÕûÊý¡£ÆäÖÐ__softirq_activeºÍ__softirq_mask¾ÍÊÇÓÃÓÚ´¥·¢ºÍ¿ØÖÆÈíÖжϵijÉÔ±±äÁ¿¡£
¢Ù__softirq_active±äÁ¿£º32λµÄÎÞ·ûºÅÕûÊý£¬±íʾÈíÖжÏÏòÁ¿0¡«31µÄ״̬¡£Èç¹ûbit£Ûi£Ý£¨0¡Üi¡Ü31£©Îª1£¬Ôò±íʾÈíÖжÏÏòÁ¿iÔÚij¸öCPUÉÏÒѾ±»´¥·¢¶ø´¦ÓÚactive״̬£»Îª0±íʾ´¦ÓÚ·Ç»îԾ״̬¡£
¢Ú__softirq_mask±äÁ¿£º32λµÄÎÞ·ûºÅÕûÊý£¬ÈíÖжÏÏòÁ¿µÄÆÁ±ÎÑÚÂë¡£Èç¹ûbit£Ûi£Ý£¨0¡Üi¡Ü31£©Îª1£¬Ôò±íʾʹÄÜ£¨enable£©ÈíÖжÏÏòÁ¿i£¬Îª0±íʾ¸ÃÈíÖжÏÏòÁ¿±»½ûÖ¹£¨disabled£©¡£
¸ù¾ÝϵͳÖе±Ç°µÄCPU¸öÊý£¨ÓɺêNR_CPUS±íʾ£©£¬LinuxÔÚkernel/softirq.cÎļþÖÐΪÿ¸öCPU¶¼¶¨ÒåÁËËü×Ô¼ºµÄÖжÏͳ¼ÆÐÅÏ¢½á¹¹£¬ÈçÏÂËùʾ£º
/* No separate irq_stat for s390, it is part of PSA */
#if !defined(CONFIG_ARCH_S390)
irq_cpustat_t irq_stat[NR_CPUS];
#endif /* CONFIG_ARCH_S390 */
ÕâÑù£¬Ã¿¸öCPU¶¼Ö»²Ù×÷Ëü×Ô¼ºµÄÖжÏͳ¼ÆÐÅÏ¢½á¹¹¡£¼ÙÉèÓÐÒ»¸ö±àºÅΪidµÄCPU£¬ÄÇôËüÖ»ÄܲÙ×÷Ëü×Ô¼ºµÄÖжÏͳ¼ÆÐÅÏ¢½á¹¹irq_stat£Ûid£Ý£¨0¡Üid¡ÜNR_CPUS-1£©£¬´Ó¶øʹ¸÷CPUÖ®¼ä»¥²»Ó°Ïì¡£Õâ¸öÊý×éÔÚinclude/linux/irq_cpustat.hÍ·ÎļþÖÐÒ²×÷ÁËÔÐÍÉùÃ÷¡£
l ´¥·¢ÈíÖжÏÇëÇóµÄ²Ù×÷º¯Êý
º¯Êý__cpu_raise_softirq()ÓÃÓÚÔÚ±àºÅΪcpuµÄ´¦ÀíÆ÷ÉÏ´¥·¢ÈíÖжÏÏòÁ¿nr¡£Ëüͨ¹ý½«ÏàÓ¦µÄ__softirq_active³ÉÔ±±äÁ¿ÖеÄÏàӦλÉèÖÃΪ1À´ÊµÏÖÈíÖжϴ¥·¢¡£ÈçÏÂËùʾ£¨include/linux/interrupt.h£©£º
static inline void __cpu_raise_softirq(int cpu, int nr)
{
softirq_active(cpu) |= (1action(h);
h++;
active >>= 1;
} while (active);
local_irq_disable();
active = softirq_active(cpu);
if ((active &= mask) != 0)
goto retry;
}
local_bh_enable();
/* Leave with locally disabled hard irqs. It is critical to close
* window for infinite recursion, while we help local bh count,
* it protected us. Now we are defenceless.
*/
return;
retry:
goto restart;
}
½áºÏÉÏÊöÔ´Â룬ÎÒÃÇ¿ÉÒÔ¿´³öÈíÖжϷþÎñµÄÖ´Ðйý³ÌÈçÏ£º
£¨1£©µ÷Óúêin_interrupt()À´¼ì²âµ±Ç°CPU´Ë´ÎÊÇ·ñÒѾ´¦ÓÚÖжϷþÎñÖС£¸Ãºê¶¨ÒåÔÚhardirq.h£¬Çë²Î¼û5.7½Ú¡£
£¨2£©µ÷ÓÃlocal_bh_disable()ºê½«µ±Ç°CPUµÄÖжÏͳ¼ÆÐÅÏ¢½á¹¹ÖеÄ__local_bh_count³ÉÔ±±äÁ¿¼Ó1£¬±íʾµ±Ç°CPUÒѾ´¦ÔÚÈíÖжϷþÎñ״̬¡£
£¨3£©ÓÉÓÚ½ÓÏÂÀ´Òª¶Áдµ±Ç°CPUµÄÖжÏͳ¼ÆÐÅÏ¢½á¹¹ÖеÄ__softirq_active±äÁ¿ºÍ__softirq_mask±äÁ¿£¬Òò´ËΪÁ˱£Ö¤ÕâÒ»¸ö²Ù×÷¹ý³ÌµÄÔ×ÓÐÔ£¬ÏÈÓÃlocal_irq_disable()ºê£¨Êµ¼ÊÉϾÍÊÇcliÖ¸Á¹Ø±Õµ±Ç°CPUµÄÖжϡ£
£¨4£©È»ºó£¬¶Áµ±Ç°CPUµÄ__softirq_active±äÁ¿ÖµºÍ__softirq_mask±äÁ¿Öµ¡£µ±Ä³¸öÈíÖжÏÏòÁ¿±»´¥·¢Ê±£¨¼´__softirq_active±äÁ¿ÖеÄÏàӦλ±»ÖÃ1£©£¬Ö»ÓÐ__softirq_mask±äÁ¿ÖеÄÏàӦλҲΪ1ʱ£¬ËüµÄÈíÖжϷþÎñº¯Êý²ÅÄܵõ½Ö´ÐС£Òò´Ë£¬ÐèÒª½«__softirq_active±äÁ¿ºÍ__softirq_mask±äÁ¿×÷Ò»´Î¡°Ó롱Âß¼²Ù×÷¡£
£¨5£©Èç¹ûactive±äÁ¿·Ç0£¬ËµÃ÷ÐèÒªÖ´ÐÐÈíÖжϷþÎñº¯Êý¡£Òò´Ë£º¢ÙÏȽ«µ±Ç°CPUµÄ__softirq_activeÖеÄÏàӦλÇåÁ㣬ȻºóÓÃlocal_irq_enable()ºê£¨Êµ¼ÊÉϾÍÊÇstiÖ¸Á´ò¿ªµ±Ç°CPUµÄÖжϡ£¢Ú½«¾Ö²¿±äÁ¿maskÖеÄÏàӦλÇåÁ㣬ÆäÄ¿µÄÊÇ£ºÈÃdo_softirq()º¯ÊýµÄÕâÒ»´ÎÖ´Ð⻶Ôͬһ¸öÈíÖжÏÏòÁ¿ÉϵÄÔÙ´ÎÈíÖжÏÇëÇó½øÐзþÎñ£¬¶øÊǽ«ËüÁô´ýÏÂÒ»´Îdo_softirq()Ö´ÐÐʱȥ·þÎñ£¬´Ó¶øʹdo_sottirq()º¯Êý±ÜÃâÏÝÈëÎÞÐÝÖ¹µÄÈíÖжϷþÎñÖС£¢ÛÓÃÒ»¸ödo{}whileÑ»·À´¸ù¾ÝactiveµÄֵȥִÐÐÏàÓ¦µÄÈíÖжϷþÎñº¯Êý¡£¢ÜÓÉÓÚ½ÓÏÂÀ´ÓÖÒª¼ì²âµ±Ç°CPUµÄ__softirq_active±äÁ¿£¬Òò´ËÔÙÒ»´Îµ÷ÓÃlocal_irq_disable()ºê¹Ø±Õµ±Ç°CPUµÄÖжϡ£¢Ý¶ÁÈ¡µ±Ç°CPUµÄ__softirq_active±äÁ¿µÄÖµ£¬²¢½«ËüÓë¾Ö²¿±äÁ¿mask½øÐÐÓë²Ù×÷£¬ÒÔ¿´¿´ÊÇ·ñÓÖÓÐÆäËûÈíÖжϷþÎñ±»´¥·¢ÁË£¨±ÈÈçÇ°ÃæËù˵µÄÄÇÖÖÇéÐΣ©¡£Èç¹ûÓеĻ°£¬ÄǾÍÌøתµ½entry³ÌÐò¶Î£¨Êµ¼ÊÉÏÊÇÌøתµ½restart³ÌÐò¶Î£©ÖØÐÂÖ´ÐÐÈíÖжϷþÎñ¡£Èç¹ûûÓеĻ°£¬ÄÇô´Ë´ÎÈíÖжϷþÎñ¹ý³Ì¾ÍÐû¸æ½áÊø¡£
£¨6£©×îºó£¬Í¨¹ýlocal_bh_enable()ºê½«µ±Ç°CPUµÄ__local_bh_count±äÁ¿Öµ¼õ1£¬±íʾµ±Ç°CPUÒѾÀ뿪ÈíÖжϷþÎñ״̬¡£ºêlocal_bh_enable()Ò²¶¨ÒåÔÚinclude/asm-i386/softirq.hÍ·ÎļþÖС£
6£®2 tasklet»úÖÆ
Tasklet»úÖÆÊÇÒ»ÖÖ½ÏΪÌØÊâµÄÈíÖжϡ£TaskletÒ»´ÊµÄÔÒâÊÇ¡°Ð¡Æ¬ÈÎÎñ¡±µÄÒâ˼£¬ÕâÀïÊÇָһС¶Î¿ÉÖ´ÐеĴúÂ룬ÇÒͨ³£ÒÔº¯ÊýµÄÐÎʽ³öÏÖ¡£ÈíÖжÏÏòÁ¿HI_SOFTIRQºÍTASKLET_SOFTIRQ¾ùÊÇÓÃtasklet»úÖÆÀ´ÊµÏֵġ£
´ÓijÖ̶ֳÈÉϽ²£¬tasklet»úÖÆÊÇLinuxÄں˶ÔBH»úÖƵÄÒ»ÖÖÀ©Õ¹¡£ÔÚ2.4ÄÚºËÒýÈëÁËsoftirq»úÖƺó£¬ÔÓеÄBH»úÖÆÕýÊÇͨ¹ýtasklet»úÖÆÕâ¸öÇÅÁºÀ´ÄÉÈësoftirq»úÖƵÄÕûÌå¿ò¼ÜÖеġ£ÕýÊÇÓÉÓÚÕâÖÖÀúÊ·µÄÑÓÉì¹Øϵ£¬Ê¹µÃtasklet»úÖÆÓëÒ»°ãÒâÒåÉϵÄÈíÖжÏÓÐËù²»Í¬£¬¶ø³ÊÏÖ³öÒÔÏÂÁ½¸öÏÔÖøµÄÌص㣺
1. ÓëÒ»°ãµÄÈíÖжϲ»Í¬£¬Ä³Ò»¶Îtasklet´úÂëÔÚij¸öʱ¿ÌÖ»ÄÜÔÚÒ»¸öCPUÉÏÔËÐУ¬¶ø²»ÏñÒ»°ãµÄÈíÖжϷþÎñº¯Êý£¨¼´softirq_action½á¹¹ÖеÄactionº¯ÊýÖ¸Õ룩ÄÇÑù----ÔÚͬһʱ¿Ì¿ÉÒÔ±»¶à¸öCPU²¢·¢µØÖ´ÐС£
2. ÓëBH»úÖƲ»Í¬£¬²»Í¬µÄtasklet´úÂëÔÚͬһʱ¿Ì¿ÉÒÔÔÚ¶à¸öCPUÉϲ¢·¢µØÖ´ÐУ¬¶ø²»ÏñBH»úÖÆÄÇÑù±ØÐëÑϸñµØ´®Ðл¯Ö´ÐУ¨Ò²¼´ÔÚͬһʱ¿ÌϵͳÖÐÖ»ÄÜÓÐÒ»¸öCPUÖ´ÐÐBHº¯Êý£©¡£
6£®2£®1 taskletÃèÊö·û
LinuxÓÃÊý¾Ý½á¹¹tasklet_structÀ´ÃèÊöÒ»¸ötasklet¡£¸ÃÊý¾Ý½á¹¹¶¨ÒåÔÚinclude/linux/interrupt.hÍ·ÎļþÖС£ÈçÏÂËùʾ£º
struct tasklet_struct
{
struct tasklet_struct *next;
unsigned long state;
atomic_t count;
void (*func)(unsigned long);
unsigned long data;
};
¸÷³ÉÔ±µÄº¬ÒåÈçÏ£º
£¨1£©nextÖ¸Õ룺ָÏòÏÂÒ»¸ötaskletµÄÖ¸Õë¡£
£¨2£©state£º¶¨ÒåÁËÕâ¸ötaskletµÄµ±Ç°×´Ì¬¡£ÕâÒ»¸ö32λµÄÎÞ·ûºÅ³¤ÕûÊý£¬µ±Ç°Ö»Ê¹ÓÃÁËbit£Û1£ÝºÍbit£Û0£ÝÁ½¸ö״̬λ¡£ÆäÖУ¬bit£Û1£Ý£½1±íʾÕâ¸ötaskletµ±Ç°ÕýÔÚij¸öCPUÉϱ»Ö´ÐУ¬Ëü½ö¶ÔSMPϵͳ²ÅÓÐÒâÒ壬Æä×÷ÓþÍÊÇΪÁË·ÀÖ¹¶à¸öCPUͬʱִÐÐÒ»¸ötaskletµÄÇéÐγöÏÖ£»bit£Û0£Ý£½1±íʾÕâ¸ötaskletÒѾ±»µ÷¶ÈÈ¥µÈ´ýÖ´ÐÐÁË¡£¶ÔÕâÁ½¸ö״̬λµÄºê¶¨ÒåÈçÏÂËùʾ£¨interrupt.h£©£º
enum
{
TASKLET_STATE_SCHED, /* Tasklet is scheduled for execution */
TASKLET_STATE_RUN /* Tasklet is running (SMP only) */
};
£¨3£©Ô×Ó¼ÆÊýcount£º¶ÔÕâ¸ötaskletµÄÒýÓüÆÊýÖµ¡£NOTE£¡Ö»Óе±countµÈÓÚ0ʱ£¬tasklet´úÂë¶Î²ÅÄÜÖ´ÐУ¬Ò²¼´´ËʱtaskletÊDZ»Ê¹Äܵģ»Èç¹ûcount·ÇÁ㣬ÔòÕâ¸ötaskletÊDZ»½ûÖ¹µÄ¡£ÈκÎÏëÒªÖ´ÐÐÒ»¸ötasklet´úÂë¶ÎµÄÈ˶¼Ê×ÏȱØÐëÏȼì²éÆäcount³ÉÔ±ÊÇ·ñΪ0¡£
£¨4£©º¯ÊýÖ¸Õëfunc£ºÖ¸ÏòÒÔº¯ÊýÐÎʽ±íÏֵĿÉÖ´ÐÐtasklet´úÂë¶Î¡£
£¨5£©data£ºº¯ÊýfuncµÄ²ÎÊý¡£ÕâÊÇÒ»¸ö32λµÄÎÞ·ûºÅÕûÊý£¬Æä¾ßÌ庬Òå¿É¹©funcº¯Êý×ÔÐнâÊÍ£¬±ÈÈ罫Æä½âÊͳÉÒ»¸öÖ¸Ïòij¸öÓû§×Ô¶¨ÒåÊý¾Ý½á¹¹µÄµØÖ·Öµ¡£
LinuxÔÚinterrupt.hÍ·ÎļþÖÐÓÖ¶¨ÒåÁËÁ½¸öÓÃÀ´¶¨Òåtasklet_struct½á¹¹±äÁ¿µÄ¸¨Öúºê£º
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
#define DECLARE_TASKLET_DISABLED(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }
ÏÔÈ»£¬´ÓÉÏÊöÔ´´úÂë¿ÉÒÔ¿´³ö£¬ÓÃDECLARE_TASKLETºê¶¨ÒåµÄtaskletÔÚ³õʼ»¯Ê±ÊDZ»Ê¹Äܵģ¨enabled£©£¬ÒòΪÆäcount³ÉԱΪ0¡£¶øÓÃDECLARE_TASKLET_DISABLEDºê¶¨ÒåµÄtaskletÔÚ³õʼʱÊDZ»½ûÖ¹µÄ£¨disabled£©£¬ÒòΪÆäcountµÈÓÚ1¡£
6£®2£®2 ¸Ä±äÒ»¸ötasklet״̬µÄ²Ù×÷
ÔÚÕâÀtasklet״ָ̬Á½¸ö·½Ã棺£¨1£©state³ÉÔ±Ëù±íʾµÄÔËÐÐ״̬£»£¨2£©count³ÉÔ±¾ö¶¨µÄʹÄÜ£¯½ûֹ״̬¡£
£¨1£©¸Ä±äÒ»¸ötaskletµÄÔËÐÐ״̬
state³ÉÔ±ÖеÄbit£Û0£Ý±íʾһ¸ötaskletÊÇ·ñÒѱ»µ÷¶ÈÈ¥µÈ´ýÖ´ÐУ¬bit£Û1£Ý±íʾһ¸ötaskletÊÇ·ñÕýÔÚij¸öCPUÉÏÖ´ÐС£¶ÔÓÚstate±äÁ¿ÖÐijλµÄ¸Ä±ä±ØÐëÊÇÒ»¸öÔ×Ó²Ù×÷£¬Òò´Ë¿ÉÒÔÓö¨ÒåÔÚinclude/asm/bitops.hÍ·ÎļþÖеÄλ²Ù×÷À´½øÐС£
ÓÉÓÚbit£Û1£ÝÕâһ루¼´TASKLET_STATE_RUN£©½ö½ö¶ÔÓÚSMPϵͳ²ÅÓÐÒâÒ壬Òò´ËLinuxÔÚInterrupt.hÍ·ÎļþÖÐÏÔʾµØ¶¨ÒåÁ˶ÔTASKLET_STATE_RUNλµÄ²Ù×÷¡£ÈçÏÂËùʾ£º
#ifdef CONFIG_SMP
#define tasklet_trylock(t) (!test_and_set_bit(TASKLET_STATE_RUN, &(t)->state))
#define tasklet_unlock_wait(t) while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { /* NOTHING */ }
#define tasklet_unlock(t) clear_bit(TASKLET_STATE_RUN, &(t)->state)
#else
#define tasklet_trylock(t) 1
#define tasklet_unlock_wait(t) do { } while (0)
#define tasklet_unlock(t) do { } while (0)
#endif
ÏÔÈ»£¬ÔÚSMPϵͳͬ£¬tasklet_trylock()ºê½«°ÑÒ»¸ötasklet_struct½á¹¹±äÁ¿ÖеÄstate³ÉÔ±ÖеÄbit£Û1£ÝλÉèÖóÉ1£¬Í¬Ê±»¹·µ»Øbit£Û1£ÝλµÄ·Ç¡£Òò´Ë£¬Èç¹ûbit£Û1£ÝλÔÓÐֵΪ1£¨±íʾÁíÍâÒ»¸öCPUÕýÔÚÖ´ÐÐÕâ¸ötasklet´úÂ룩£¬ÄÇôtasklet_trylock()ºê½«·µ»ØÖµ0£¬Ò²¾Í±íʾÉÏËø²»³É¹¦¡£Èç¹ûbit£Û1£ÝλµÄÔÓÐֵΪ0£¬ÄÇôtasklet_trylock()ºê½«·µ»ØÖµ1£¬±íʾ¼ÓËø³É¹¦¡£¶øÔÚµ¥CPUϵͳÖУ¬tasklet_trylock()ºê×ÜÊÇ·µ»ØΪ1¡£
ÈκÎÏëÒªÖ´ÐÐij¸ötasklet´úÂëµÄ³ÌÐò¶¼±ØÐëÊ×Ïȵ÷Óúêtasklet_trylock()À´ÊÔͼ¶ÔÕâ¸ötasklet½øÐÐÉÏËø£¨¼´ÉèÖÃTASKLET_STATE_RUN룩£¬ÇÒÖ»ÄÜÔÚÉÏËø³É¹¦µÄÇé¿öϲÅÄÜÖ´ÐÐÕâ¸ötasklet¡£½¨Ò飡¼´Ê¹ÄãµÄ³ÌÐòÖ»ÔÚCPUϵͳÉÏÔËÐУ¬ÄãÒ²ÒªÔÚÖ´ÐÐtasklet֮ǰµ÷ÓÃtasklet_trylock()ºê£¬ÒÔ±ãʹÄãµÄ´úÂë»ñµÃÁ¼ºÃ¿ÉÒÆÖ²ÐÔ¡£
ÔÚSMPϵͳÖУ¬tasklet_unlock_wait()ºê½«Ò»Ö±²»Í£µØ²âÊÔTASKLET_STATE_RUNλµÄÖµ£¬Ö±µ½¸ÃλµÄÖµ±äΪ0£¨¼´Ò»Ö±µÈ´ýµ½½âËø£©£¬¼ÙÈ磺CPU0ÕýÔÚÖ´ÐÐtasklet AµÄ´úÂ룬ÔÚ´ËÆڼ䣬CPU1Ò²ÏëÖ´ÐÐtasklet AµÄ´úÂ룬µ«CPU1·¢ÏÖtasklet AµÄTASKLET_STATE_RUNλΪ1£¬ÓÚÊÇËü¾Í¿ÉÒÔͨ¹ýtasklet_unlock_wait()ºêµÈ´ýtasklet A±»½âËø£¨Ò²¼´TASKLET_STATE_RUNλ±»ÇåÁ㣩¡£ÔÚµ¥CPUϵͳÖУ¬ÕâÊÇÒ»¸ö¿Õ²Ù×÷¡£
ºêtasklet_unlock()ÓÃÀ´¶ÔÒ»¸ötasklet½øÐнâËø²Ù×÷£¬Ò²¼´½«TASKLET_STATE_RUNλÇåÁã¡£ÔÚµ¥CPUϵͳÖУ¬ÕâÊÇÒ»¸ö¿Õ²Ù×÷¡£
£¨2£©Ê¹ÄÜ£¯½ûÖ¹Ò»¸ötasklet
ʹÄÜÓë½ûÖ¹²Ù×÷ÍùÍù×ÜÊdzɶԵر»µ÷Óõģ¬tasklet_disable()º¯ÊýÈçÏ£¨interrupt.h£©£º
static inline void tasklet_disable(struct tasklet_struct *t)
{
tasklet_disable_nosync(t);
tasklet_unlock_wait(t);
}
º¯Êýtasklet_disable_nosync()Ò²ÊÇÒ»¸ö¾²Ì¬inlineº¯Êý£¬Ëü¼òµ¥µØͨ¹ýÔ×Ó²Ù×÷½«count³ÉÔ±±äÁ¿µÄÖµ¼õ1¡£ÈçÏÂËùʾ£¨interrupt.h£©£º
static inline void tasklet_disable_nosync(struct tasklet_struct *t)
{
atomic_inc(&t->count);
}
º¯Êýtasklet_enable()ÓÃÓÚʹÄÜÒ»¸ötasklet£¬ÈçÏÂËùʾ£¨interrupt.h£©£º
static inline void tasklet_enable(struct tasklet_struct *t)
{
atomic_dec(&t->count);
}
6£®2£®3 taskletÃèÊö·ûµÄ³õʼ»¯ÓëɱËÀ
º¯Êýtasklet_init()ÓÃÀ´³õʼ»¯Ò»¸öÖ¸¶¨µÄtaskletÃèÊö·û£¬ÆäÔ´ÂëÈçÏÂËùʾ£¨kernel/softirq.c£©£º
void tasklet_init(struct tasklet_struct *t,
void (*func)(unsigned long), unsigned long data)
{
t->func = func;
t->data = data;
t->state = 0;
atomic_set(&t->count, 0);
}
º¯Êýtasklet_kill()ÓÃÀ´½«Ò»¸öÒѾ±»µ÷¶ÈÁ˵ÄtaskletɱËÀ£¬¼´½«Æä»Ö¸´µ½Î´µ÷¶ÈµÄ״̬¡£ÆäÔ´ÂëÈçÏÂËùʾ£¨kernel/softirq.c£©£º
void tasklet_kill(struct tasklet_struct *t)
{
if (in_interrupt())
printk("Attempt to kill tasklet from interrupt\n");
while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
current->state = TASK_RUNNING;
do {
current->policy |= SCHED_YIELD;
schedule();
} while (test_bit(TASKLET_STATE_SCHED, &t->state));
}
tasklet_unlock_wait(t);
clear_bit(TASKLET_STATE_SCHED, &t->state);
}
6£®2£®4 tasklet¶ÔÁÐ
¶à¸ötasklet¿ÉÒÔͨ¹ýtaskletÃèÊö·ûÖеÄnext³ÉÔ±Ö¸ÕëÁ´½Ó³ÉÒ»¸öµ¥Ïò¶ÔÁС£Îª´Ë£¬LinuxרÃÅÔÚÍ·Îļþinclude/linux/interrupt.hÖж¨ÒåÁËÊý¾Ý½á¹¹tasklet_headÀ´ÃèÊöÒ»¸ötasklet¶ÔÁеÄÍ·²¿Ö¸Õë¡£ÈçÏÂËùʾ£º
struct tasklet_head
{
struct tasklet_struct *list;
} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
¾¡¹Ütasklet»úÖÆÊÇÌض¨ÓÚÈíÖжÏÏòÁ¿HI_SOFTIRQºÍTASKLET_SOFTIRQµÄÒ»ÖÖʵÏÖ£¬µ«ÊÇtasklet»úÖÆÈÔÈ»ÊôÓÚsoftirq»úÖƵÄÕûÌå¿ò¼Ü·¶Î§Äڵģ¬Òò´Ë£¬ËüµÄÉè¼ÆÓëʵÏÖÈÔÈ»±ØÐë¼á³Ö¡°Ë´¥·¢£¬ËÖ´ÐС±µÄ˼Ï롣Ϊ´Ë£¬LinuxΪϵͳÖеÄÿһ¸öCPU¶¼¶¨ÒåÁËÒ»¸ötasklet¶ÔÁÐÍ·²¿£¬À´±íʾӦ¸ÃÓи÷¸öCPU¸ºÔðÖ´ÐеÄtasklet¶ÔÁС£ÈçÏÂËùʾ£¨kernel/softirq.c£©£º
struct tasklet_head tasklet_vec[NR_CPUS] __cacheline_aligned;
struct tasklet_head tasklet_hi_vec[NR_CPUS] __cacheline_aligned;
ÆäÖУ¬tasklet_vec£Û£ÝÊý×éÓÃÓÚÈíÖжÏÏòÁ¿TASKLET_SOFTIRQ£¬¶øtasklet_hi_vec£Û£ÝÊý×éÔòÓÃÓÚÈíÖжÏÏòÁ¿HI_SOFTIRQ¡£Ò²¼´£¬Èç¹ûCPUi£¨0¡Üi¡ÜNR_CPUS-1£©´¥·¢ÁËÈíÖжÏÏòÁ¿TASKLET_SOFTIRQ£¬ÄÇô¶ÔÁÐtasklet_vec£Ûi£ÝÖеÄÿһ¸ötasklet¶¼½«ÔÚCPUi·þÎñÓÚÈíÖжÏÏòÁ¿TASKLET_SOFTIRQʱ±»CPUiËùÖ´ÐС£Í¬ÑùµØ£¬Èç¹ûCPUi£¨0¡Üi¡ÜNR_CPUS-1£©´¥·¢ÁËÈíÖжÏÏòÁ¿HI_SOFTIRQ£¬ÄÇô¶ÓÁÐtasklet_vec£Ûi£ÝÖеÄÿһ¸ötasklet¶¼½«CPUiÔÚ¶ÔÈíÖжÏÏòÁ¿HI_SOFTIRQ½øÐзþÎñʱ±»CPUiËùÖ´ÐС£
¶ÓÁÐtasklet_vec£ÛI£ÝºÍtasklet_hi_vec£ÛI£ÝÖеĸ÷¸ötaskletÊÇÔõÑù±»ËùCPUiËùÖ´ÐеÄÄØ£¿Æä¹Ø¼ü¾ÍÊÇÈíÖжÏÏòÁ¿TASKLET_SOFTIRQºÍHI_SOFTIRQµÄÈíÖжϷþÎñ³ÌÐò----tasklet_action()º¯ÊýºÍtasklet_hi_action()º¯Êý¡£ÏÂÃæÎÒÃǾÍÀ´·ÖÎöÕâÁ½¸öº¯Êý¡£
6£®2£®5 ÈíÖжÏÏòÁ¿TASKLET_SOFTIRQºÍHI_SOFTIRQ
LinuxΪÈíÖжÏÏòÁ¿TASKLET_SOFTIRQºÍHI_SOFTIRQʵÏÖÁËרÓõĴ¥·¢º¯ÊýºÍÈíÖжϷþÎñº¯Êý¡£ÆäÖУ¬tasklet_schedule()º¯ÊýºÍtasklet_hi_schedule()º¯Êý·Ö±ðÓÃÀ´ÔÚµ±Ç°CPUÉÏ´¥·¢ÈíÖжÏÏòÁ¿TASKLET_SOFTIRQºÍHI_SOFTIRQ£¬²¢°ÑÖ¸¶¨µÄtasklet¼ÓÈ뵱ǰCPUËù¶ÔÓ¦µÄtasklet¶ÓÁÐÖÐÈ¥µÈ´ýÖ´ÐС£¶øtasklet_action()º¯ÊýºÍtasklet_hi_action()º¯ÊýÔò·Ö±ðÊÇÈíÖжÏÏòÁ¿TASKLET_SOFTIRQºÍHI_SOFTIRQµÄÈíÖжϷþÎñº¯Êý¡£ÔÚ³õʼ»¯º¯Êýsoftirq_init()ÖУ¬ÕâÁ½¸öÈíÖжÏÏòÁ¿¶ÔÓ¦µÄÃèÊö·ûsoftirq_vec£Û0£ÝºÍsoftirq_vec£Û3£ÝÖеÄactionº¯ÊýÖ¸Õë¾Í±»·Ö±ð³õʼ»¯³ÉÖ¸Ïòº¯Êýtasklet_hi_action()ºÍº¯Êýtasklet_action£¨£©¡£
£¨1£©ÈíÖжÏÏòÁ¿TASKLET_SOFTIRQµÄ´¥·¢º¯Êýtasklet_schedule£¨£©
¸Ãº¯ÊýʵÏÖÔÚinclude/linux/interrupt.hÍ·ÎļþÖУ¬ÊÇÒ»¸öinlineº¯Êý¡£ÆäÔ´ÂëÈçÏÂËùʾ£º
static inline void tasklet_schedule(struct tasklet_struct *t)
{
if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
int cpu = smp_processor_id();
unsigned long flags;
local_irq_save(flags);
t->next = tasklet_vec[cpu].list;
tasklet_vec[cpu].list = t;
__cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);
local_irq_restore(flags);
}
}
¸Ãº¯ÊýµÄ²ÎÊýtÖ¸ÏòÒªÔÚµ±Ç°CPUÉϱ»Ö´ÐеÄtasklet¡£¶Ô¸Ãº¯ÊýµÄNOTEÈçÏ£º
¢Ùµ÷ÓÃtest_and_set_bit()º¯Êý½«´ýµ÷¶ÈµÄtaskletµÄstate³ÉÔ±±äÁ¿µÄbit£Û0£Ý루Ҳ¼´TASKLET_STATE_SCHED룩ÉèÖÃΪ1£¬¸Ãº¯Êýͬʱ»¹·µ»ØTASKLET_STATE_SCHEDλµÄÔÓÐÖµ¡£Òò´ËÈç¹ûbit£Û0£ÝΪµÄÔÓÐÖµÒѾΪ1£¬ÄǾÍ˵Ã÷Õâ¸ötaskletÒѾ±»µ÷¶Èµ½ÁíÒ»¸öCPUÉÏÈ¥µÈ´ýÖ´ÐÐÁË¡£ÓÉÓÚÒ»¸ötaskletÔÚijһ¸öʱ¿ÌÖ»ÄÜÓÉÒ»¸öCPUÀ´Ö´ÐУ¬Òò´Ëtasklet_schedule()º¯ÊýʲôҲ²»×ö¾ÍÖ±½Ó·µ»ØÁË¡£·ñÔò£¬¾Í¼ÌÐøÏÂÃæµÄµ÷¶È²Ù×÷¡£
¢ÚÊ×ÏÈ£¬µ÷ÓÃlocal_irq_save()º¯ÊýÀ´¹Ø±Õµ±Ç°CPUµÄÖжϣ¬ÒÔ±£Ö¤ÏÂÃæµÄ²½ÖèÔÚµ±Ç°CPUÉÏÔ×ӵر»Ö´ÐС£
¢ÛÈ»ºó£¬½«´ýµ÷¶ÈµÄtaskletÌí¼Óµ½µ±Ç°CPU¶ÔÓ¦µÄtasklet¶ÓÁеÄÊײ¿¡£
¢Ü½Ó×Å£¬µ÷ÓÃ__cpu_raise_softirq()º¯ÊýÔÚµ±Ç°CPUÉÏ´¥·¢ÈíÖжÏÇëÇóTASKLET_SOFTIRQ¡£
¢Ý×îºó£¬µ÷ÓÃlocal_irq_restore()º¯ÊýÀ´¿ªµ±Ç°CPUµÄÖжϡ£
£¨2£©ÈíÖжÏÏòÁ¿TASKLET_SOFTIRQµÄ·þÎñ³ÌÐòtasklet_action£¨£©
º¯Êýtasklet_action()ÊÇtasklet»úÖÆÓëÈíÖжÏÏòÁ¿TASKLET_SOFTIRQµÄÁªÏµÅ¦´ø¡£ÕýÊǸú¯Êý½«µ±Ç°CPUµÄtasklet¶ÓÁÐÖеĸ÷¸ötasklet·Åµ½µ±Ç°CPUÉÏÀ´Ö´Ðеġ£¸Ãº¯ÊýʵÏÖÔÚkernel/softirq.cÎļþÖУ¬ÆäÔ´´úÂëÈçÏ£º
static void tasklet_action(struct softirq_action *a)
{
int cpu = smp_processor_id();
struct tasklet_struct *list;
local_irq_disable();
list = tasklet_vec[cpu].list;
tasklet_vec[cpu].list = NULL;
local_irq_enable();
while (list != NULL) {
struct tasklet_struct *t = list;
list = list->next;
if (tasklet_trylock(t)) {
if (atomic_read(&t->count) == 0) {
clear_bit(TASKLET_STATE_SCHED, &t->state);
t->func(t->data);
/*
* talklet_trylock() uses test_and_set_bit that imply
* an mb when it returns zero, thus we need the explicit
* mb only here: while closing the critical section.
*/
#ifdef CONFIG_SMP
smp_mb__before_clear_bit();
#endif
tasklet_unlock(t);
continue;
}
tasklet_unlock(t);
}
local_irq_disable();
t->next = tasklet_vec[cpu].list;
tasklet_vec[cpu].list = t;
__cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);
local_irq_enable();
}
}
×¢ÊÍÈçÏ£º
¢ÙÊ×ÏÈ£¬ÔÚµ±Ç°CPU¹ØÖжϵÄÇé¿öÏ£¬¡°Ô×Ó¡±µØ¶ÁÈ¡µ±Ç°CPUµÄtasklet¶ÓÁÐÍ·²¿Ö¸Õ룬½«Æä±£´æµ½¾Ö²¿±äÁ¿listÖ¸ÕëÖУ¬È»ºó½«µ±Ç°CPUµÄtasklet¶ÓÁÐÍ·²¿Ö¸ÕëÉèÖÃΪNULL£¬ÒÔ±íʾÀíÂÛÉϵ±Ç°CPU½«²»ÔÙÓÐtaskletÐèÒªÖ´ÐУ¨µ«×îºóµÄʵ¼Ê½á¹ûÈ´²¢²»Ò»¶¨Èç´Ë£¬ÏÂÃ潫»á¿´µ½£©¡£
¢ÚÈ»ºó£¬ÓÃÒ»¸öwhile{}Ñ»·À´±éÀúÓÉlistËùÖ¸ÏòµÄtasklet¶ÓÁУ¬¶ÓÁÐÖеĸ÷¸öÔªËؾÍÊǽ«ÔÚµ±Ç°CPUÉÏÖ´ÐеÄtasklet¡£Ñ»·ÌåµÄÖ´Ðв½ÖèÈçÏ£º
l ÓÃÖ¸ÕëtÀ´±íʾµ±Ç°¶ÓÁÐÔªËØ£¬¼´µ±Ç°ÐèÒªÖ´ÐеÄtasklet¡£
l ¸üÐÂlistÖ¸ÕëΪlist->next£¬Ê¹ËüÖ¸ÏòÏÂÒ»¸öÒªÖ´ÐеÄtasklet¡£
l ÓÃtasklet_trylock()ºêÊÔͼ¶Ôµ±Ç°ÒªÖ´ÐеÄtasklet£¨ÓÉÖ¸ÕëtËùÖ¸Ïò£©½øÐмÓËø£¬Èç¹û¼ÓËø³É¹¦£¨µ±Ç°Ã»ÓÐÈκÎÆäËûCPUÕýÔÚÖ´ÐÐÕâ¸ötasklet£©£¬ÔòÓÃÔ×Ó¶Áº¯Êýatomic_read()½øÒ»²½ÅжÏcount³ÉÔ±µÄÖµ¡£Èç¹ûcountΪ0£¬ËµÃ÷Õâ¸ötaskletÊÇÔÊÐíÖ´Ðеģ¬ÓÚÊÇ£º£¨1£©ÏÈÇå³ýTASKLET_STATE_SCHEDλ£»£¨2£©È»ºó£¬µ÷ÓÃÕâ¸ötaskletµÄ¿ÉÖ´Ðк¯Êýfunc£»£¨3£©Ö´ÐÐbarrier()²Ù×÷£»£¨4£©µ÷Óúêtasklet_unlock()À´Çå³ýTASKLET_STATE_RUNλ¡££¨5£©×îºó£¬Ö´ÐÐcontinueÓï¾äÌø¹ýÏÂÃæµÄ²½Ö裬»Øµ½whileÑ»·¼ÌÐø±éÀú¶ÓÁÐÖеÄÏÂÒ»¸öÔªËØ¡£Èç¹ûcount²»Îª0£¬ËµÃ÷Õâ¸ötaskletÊǽûÖ¹ÔËÐеģ¬ÓÚÊǵ÷ÓÃtasklet_unlock()Çå³ýÇ°ÃæÓÃtasklet_trylock()ÉèÖõÄTASKLET_STATE_RUNλ¡£
l Èç¹ûtasklet_trylock()¼ÓËø²»³É¹¦£¬»òÕßÒòΪµ±Ç°taskletµÄcountÖµ·Ç0¶ø²»ÔÊÐíÖ´ÐÐʱ£¬ÎÒÃDZØÐ뽫Õâ¸ötaskletÖØзŻص½µ±Ç°CPUµÄtasklet¶ÓÁÐÖУ¬ÒÔÁô´ýÕâ¸öCPUÏ´ηþÎñÈíÖжÏÏòÁ¿TASKLET_SOFTIRQʱÔÙÖ´ÐС£Îª´Ë½øÐÐÕâÑù¼¸²½²Ù×÷£º£¨1£©ÏȹØCPUÖжϣ¬ÒÔ±£Ö¤ÏÂÃæ²Ù×÷µÄÔ×ÓÐÔ¡££¨2£©°ÑÕâ¸ötaskletÖØзŻص½µ±Ç°CPUµÄtasklet¶ÓÁеÄÊײ¿£»£¨3£©µ÷ÓÃ__cpu_raise_softirq()º¯ÊýÔÚµ±Ç°CPUÉÏÔÙ´¥·¢Ò»´ÎÈíÖжÏÇëÇóTASKLET_SOFTIRQ£»£¨4£©¿ªÖжϡ£
l ×îºó£¬»Øµ½whileÑ»·¼ÌÐø±éÀú¶ÓÁС£
£¨3£©ÈíÖжÏÏòÁ¿HI_SOFTIRQµÄ´¥·¢º¯Êýtasklet_hi_schedule()
¸Ãº¯ÊýÓëtasklet_schedule()¼¸ºõÏàͬ£¬ÆäÔ´ÂëÈçÏ£¨include/linux/interrupt.h£©£º
static inline void tasklet_hi_schedule(struct tasklet_struct *t)
{
if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
int cpu = smp_processor_id();
unsigned long flags;
local_irq_save(flags);
t->next = tasklet_hi_vec[cpu].list;
tasklet_hi_vec[cpu].list = t;
__cpu_raise_softirq(cpu, HI_SOFTIRQ);
local_irq_restore(flags);
}
}
£¨4£©ÈíÖжÏÏòÁ¿HI_SOFTIRQµÄ·þÎñº¯Êýtasklet_hi_action£¨£©
¸Ãº¯ÊýÓëtasklet_action()º¯Êý¼¸ºõÏàͬ£¬ÆäÔ´ÂëÈçÏ£¨kernel/softirq.c£©£º
static void tasklet_hi_action(struct softirq_action *a)
{
int cpu = smp_processor_id();
struct tasklet_struct *list;
local_irq_disable();
list = tasklet_hi_vec[cpu].list;
tasklet_hi_vec[cpu].list = NULL;
local_irq_enable();
while (list != NULL) {
struct tasklet_struct *t = list;
list = list->next;
if (tasklet_trylock(t)) {
if (atomic_read(&t->count) == 0) {
clear_bit(TASKLET_STATE_SCHED, &t->state);
t->func(t->data);
tasklet_unlock(t);
continue;
}
tasklet_unlock(t);
}
local_irq_disable();
t->next = tasklet_hi_vec[cpu].list;
tasklet_hi_vec[cpu].list = t;
__cpu_raise_softirq(cpu, HI_SOFTIRQ);
local_irq_enable();
}
}
6£®3 Bottom Half»úÖÆ
Bottom Half»úÖÆÔÚеÄsoftirq»úÖÆÖб»±£ÁôÏÂÀ´£¬²¢×÷Ϊsoftirq¿ò¼ÜµÄÒ»²¿·Ö¡£ÆäʵÏÖÒ²Ëƺõ¸üΪ¸´ÔÓЩ£¬ÒòΪËüÊÇͨ¹ýtasklet»úÖÆÕâ¸öÖнéÇÅÁºÀ´ÄÉÈësoftirq¿ò¼ÜÖеġ£Êµ¼ÊÉÏ£¬ÈíÖжÏÏòÁ¿HI_SOFTIRQÊÇÄÚºËרÓÃÓÚÖ´ÐÐBHº¯ÊýµÄ¡£
6£®3£®1 Êý¾Ý½á¹¹µÄ¶¨Òå
ÔÓеÄ32¸öBHº¯ÊýÖ¸Õë±»±£Áô£¬¶¨ÒåÔÚkernel/softirq.cÎļþÖУº
static void (*bh_base[32])(void);
µ«ÊÇ£¬Ã¿¸öBHº¯Êý¶¼¶ÔÓ¦ÓÐÒ»¸ötasklet£¬²¢ÓÉtaskletµÄ¿ÉÖ´Ðк¯ÊýfuncÀ´¸ºÔðµ÷ÓÃÏàÓ¦µÄbhº¯Êý£¨funcº¯ÊýµÄ²ÎÊýÖ¸¶¨µ÷ÓÃÄÄÒ»¸öBHº¯Êý£©¡£Óë32¸öBHº¯ÊýÖ¸ÕëÏà¶ÔÓ¦µÄtaskletµÄ¶¨ÒåÈçÏÂËùʾ£¨kernel/softirq.c£©£º
struct tasklet_struct bh_task_vec[32];
ÉÏÊötaskletÊý×éʹϵͳȫ¾ÖµÄ£¬Ëü¶ÔËùÓеÄCPU¾ù¿É¼û¡£ÓÉÓÚÔÚijһ¸öʱ¿ÌÖ»ÄÜÓÐÒ»¸öCPUÔÚÖ´ÐÐBHº¯Êý£¬Òò´Ë¶¨ÒåÒ»¸öÈ«¾ÖµÄ×ÔÐýËøÀ´±£»¤BHº¯Êý£¬ÈçÏÂËùʾ£¨kernel/softirq.c£©£º
spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
6£®3£®2 ³õʼ»¯
ÔÚsoftirq»úÖƵijõʼ»¯º¯Êýsoftirq_init()Öн«bh_task_vec£Û32£ÝÊý×éÖеÄÿһ¸ötaskletÖеÄfuncº¯ÊýÖ¸Õ붼ÉèÖÃΪָÏòͬһ¸öº¯Êýbh_action£¬¶ødata³ÉÔ±£¨Ò²¼´funcº¯ÊýµÄµ÷ÓòÎÊý£©Ôò±»ÉèÖóɸÃtaskletÔÚÊý×éÖеÄË÷ÒýÖµ£¬ÈçÏÂËùʾ£º
void __init softirq_init()
{
¡¡
for (i=0; isync)) {
unsigned long flags;
spin_lock_irqsave(&tqueue_lock, flags);
list_add_tail(&bh_pointer->list, bh_list);
spin_unlock_irqrestore(&tqueue_lock, flags);
ret = 1;
}
return ret;
}
6£®4£®3 ÔËÐÐÈÎÎñ¶ÓÁÐ
º¯Êýrun_task_queue()ÓÃÓÚʵÏÖÖ¸¶¨µÄÈÎÎñ¶ÓÁС£ËüÖ»ÓÐÒ»¸ö²ÎÊý£ºÖ¸Õëlist----Ö¸Ïò´ýÔËÐеÄÈÎÎñ¶ÓÁÐÍ·²¿task_queue½á¹¹±äÁ¿¡£¸Ãº¯ÊýʵÏÖÔÚtqueue.hÍ·ÎļþÖУº
static inline void run_task_queue(task_queue *list)
{
if (TQ_ACTIVE(*list))
__run_task_queue(list);
}
ÏÔÈ»£¬º¯ÊýÊ×Ïȵ÷ÓúêTQ_ACTIVE()À´ÅжϲÎÊýlistÖ¸¶¨µÄ´ýÔËÐÐÈÎÎñ¶ÓÁÐÊÇ·ñΪ¿Õ¡£Èç¹û²»Îª¿Õ£¬Ôòµ÷ÓÃ__run_task_queue()º¯ÊýÀ´Êµ¼ÊÔËÐÐÕâ¸öÓÐЧµÄÈÎÎñ¶ÓÁС£
º¯Êý__run_task_queue()ʵÏÖÔÚkernel/softirq.cÎļþÖС£¸Ãº¯Êý½«ÒÀ´Î±éÀúÈÎÎñ¶ÓÁÐÖеÄÿһ¸öÔªÊý£¬²¢µ÷ÓÃÖ´ÐÐÿһ¸öÔªÊýµÄ¿ÉÖ´Ðк¯Êý¡£ÆäÔ´ÂëÈçÏ£º
void __run_task_queue(task_queue *list)
{
struct list_head head, *next;
unsigned long flags;
spin_lock_irqsave(&tqueue_lock, flags);
list_add(&head, list);
list_del_init(list);
spin_unlock_irqrestore(&tqueue_lock, flags);
next = head.next;
while (next != &head) {
void (*f) (void *);
struct tq_struct *p;
void *data;
p = list_entry(next, struct tq_struct, list);
next = next->next;
f = p->routine;
data = p->data;
wmb();
p->sync = 0;
if (f)
f(data);
}
}
¶Ô¸Ãº¯ÊýµÄ×¢ÊÍÈçÏ£º
£¨1£©Ê×ÏÈ£¬ÓÃÒ»¸ö¾Ö²¿µÄ±íÍ·headÀ´´úÌæ²ÎÊýlistËùÖ¸ÏòµÄ±íÍ·¡£ÕâÊÇÒòΪ£ºÔÚ__run_task_queue£¨£©º¯ÊýµÄÔËÐÐÆÚ¼ä¿ÉÄÜ»¹»áÓÐеÄÈÎÎñ¼ÓÈëµ½listÈÎÎñ¶ÓÁÐÖÐÀ´£¬µ«ÊÇ__run_task_queue()º¯ÊýÏÔÈ»²»ÏëÏÝÈëÎÞÐÝÖ¹µÄ²»¶ÏÔö¼ÓµÄÈÎÎñ´¦ÀíÖУ¬Òò´ËËüÓþֲ¿µÄ±íÍ·headÀ´´úÌæ²ÎÊýlistËùÖ¸ÏòµÄ±íÍ·£¬ÒÔʹҪִÐеÄÈÎÎñ¸öÊý¹Ì¶¨»¯¡£Îª´Ë£º¢ÙÏȶÔÈ«¾ÖµÄ×ÔÐýËøtqueue_lock½øÐмÓËø£¬ÒÔʵÏÖ¶ÔÈÎÎñ¶ÓÁеĻ¥³â·ÃÎÊ£»¢Ú½«¾Ö²¿µÄ±íÍ·head¼ÓÔÚ±íÍ·£¨£ªlist£©ºÍµÚÒ»¸öÔªÊýÖ®¼ä¡£¢Û½«£¨£ªlist£©±íÍ·´Ó¶ÓÁÐÖÐÈ¥³ý£¬²¢½«Æä³õʼ»¯Îª¿Õ¡£¢Ü½â³ý×ÔÐýËøtqueue_lock¡£
£¨2£©½ÓÏÂÀ´£¬ÓÃÒ»¸öwhileÑ»·À´±éÀúÕû¸ö¶ÓÁÐhead£¬²¢µ÷ÓÃÖ´ÐÐÿһ¸ö¶ÓÁÐÔªËØÖеĺ¯Êý¡£×¢Ò⣡ÈÎÎñ¶ÓÁÐÊÇÒ»¸öË«ÏòÑ»·¶ÓÁС£
6£®4£®4 ÄÚºËÔ¤¶¨ÒåµÄÈÎÎñ¶ÓÁÐ
Bottom Half»úÖÆÓëÈÎÎñ¶ÓÁÐÊǽôÃÜÏàÁ¬µÄ¡£´ó¶àÊýBHº¯Êý¶¼ÊÇͨ¹ýµ÷ÓÃrun_task_queue()º¯ÊýÀ´Ö´ÐÐij¸öÔ¤¶¨ÒåºÃµÄÈÎÎñ¶ÓÁС£×î³£¼ûµÄÄÚºËÔ¤¶¨ÒåÈÎÎñ¶ÓÁÐÓУº
l tq_timer£º¶ÔÓ¦ÓÚTQUEUE_BH¡£
l tq_immediate£º¶ÔÓ¦ÓÚIMMEDIATE_BH¡£
l tq_disk£ºÓÃÓÚ¿éÉ豸ÈÎÎñ¡£
ÈÎÎñ¶ÓÁÐtq_timerºÍtq_immediate¶¼¶¨ÒåÔÚkernel/timer.cÎļþÖУ¬ÈçÏÂËùʾ£º
DECLARE_TASK_QUEUE(tq_timer);
DECLARE_TASK_QUEUE(tq_immediate);
BHÏòÁ¿TQUEUE_BHºÍIMMEDIATE_BHµÄBHº¯Êý·Ö±ðÊÇ£ºqueue_bh£¨£©º¯ÊýºÍimmediate_bh()º¯Êý£¬ËüÃǶ¼½ö½öÊǼòµ¥µØµ÷ÓÃrun_task_queue()º¯ÊýÀ´·Ö±ðÔËÐÐÈÎÎñ¶ÓÁÐtq_timerºÍtq_immediate£¬ÈçÏÂËùʾ£¨kernel/timer.c£©£º
void tqueue_bh(void)
{
run_task_queue(&tq_timer);
}
void immediate_bh(void)
{
run_task_queue(&tq_immediate);
}