|
源代码网推荐
FreeBSD 5 内核中断处理的最大特点是将中断处理程序在线程的上下文中运行。 为此,内核为每个注册的中断源(即vector)准备一个内核线程,即中断线程, 其任务就是等待中断的发生,一旦发生,便运行相应的中断处理程序。
FreeBSD 5这样做,有好处也有坏处。好处是可以简化线程和中断的互斥关系, 并使得中断处理可以阻塞。 坏处是每次响应中断都要进行线程调度,可能有两次线程上下文的切换 (从用户线程切到中断线程再切回来)。未来的想法是进行lazy scheduling, 即尽可能借用当前线程的上下文,只有在中断要阻塞时才进行真正的调度。
与中断有关的源代码主要在
sys/kern/kern_intr.c (与体系结构无关的中断代码) sys/i386/i386/intr_machdep.c (与i386体系结构相关的中断代码) sys/i386/isa/atpic.c (与8259A相关的.c代码) sys/i386/isa/atpic_vector.s (与8259A相关的.s代码)
Contents
1,登记IRQ中断源 1.1 数据结构与函数 1.2 8259A的登记过程 2,IRQ中断的处理过程 3, 软件中断swi 3.1 软件中断的登记 3.2 软件中断的调度
------------------------------- 1,登记IRQ中断源
1.1 数据结构与函数
中断向量表有多个vector,0-31为CPU用,32~32+15对应IRQ0~IRQ15 一个vector对应一个source,数据类型是struct intsrc 代码: /* * An interrupt source. The upper-layer code uses the PIC methods to * control a given source. The lower-layer PIC drivers can store additional * private data in a given interrupt source such as an interrupt pin number * or an I/O APIC pointer. */ struct intsrc { struct pic *is_pic; struct ithd *is_ithread; u_long *is_count; u_long *is_straycount; u_int is_index; };
其实在vector后面的是中断控制器,如8259A,I/O APIC等, 事实上,对中断源的控制实际上就是对中断控制器的操作, 因此,在struct intsrc中有成员struct pic *is_pic, 即中断控制器的操作函数表,通过这个表,可以为不同的中断控制器 定义不同的操作,达到demultiplex的作用。这里pic是 programmable interrupt controller的意思。 代码: /* * Methods that a PIC provides to mask/unmask a given interrupt source, * "turn on" the interrupt on the CPU side by setting up an IDT entry, and * return the vector associated with this source. */ struct pic { void (*pic_enable_source)(struct intsrc *); void (*pic_disable_source)(struct intsrc *); void (*pic_eoi_source)(struct intsrc *); void (*pic_enable_intr)(struct intsrc *); int (*pic_vector)(struct intsrc *); int (*pic_source_pending)(struct intsrc *); void (*pic_suspend)(struct intsrc *); void (*pic_resume)(struct intsrc *); };
系统中所有的中断源组成一个数组,由于当采用I/O APIC作为中断控制器时, 可以有191个中断号(IRQ),因此该数组大小定义为191。 代码: static struct intsrc *interrupt_sources[NUM_IO_INTS];
/* With I/O APIC"s we can have up to 191 interrupts. */ #define NUM_IO_INTS 191
所谓登记中断源,就是将实际的中断控制器的对应struct intsrc数据结构 添加到该数组中去。同时,系统为每个登记的中断源创建一个中断线程, 中断处理程序就在该线程的上下文中运行,该线程的入口函数为ithread_loop(),
struct intsrc结构成员is_ithread指向描述中断线程的数据结构struct ithd, 而struct ithd结构成员it_td指向真正的线程结构struct thread,从而将中断 与系统的调度单元线程联系起来。
代码: /* * Describe an interrupt thread. There is one of these per interrupt vector. * Note that this actually describes an interrupt source. There may or may * not be an actual kernel thread attached to a given source. */ struct ithd { struct mtx it_lock; struct thread *it_td; /* Interrupt process. */ LIST_ENTRY(ithd) it_list; /* All interrupt threads. */ TAILQ_HEAD(, intrhand) it_handlers; /* Interrupt handlers. */ struct ithd *it_interrupted; /* Who we interrupted. */ void (*it_disable)(uintptr_t); /* Enable interrupt source. */ void (*it_enable)(uintptr_t); /* Disable interrupt source. */ void *it_md; /* Hook for MD interrupt code. */ int it_flags; /* Interrupt-specific flags. */ int it_need; /* Needs service. */ uintptr_t it_vector; char it_name[MAXCOMLEN + 1]; };
/* * Register a new interrupt source with the global interrupt system. * The global interrupts need to be disabled when this function is * called. */ int intr_register_source(struct intsrc *isrc) { int error, vector;
vector = isrc->is_pic->pic_vector(isrc); if (interrupt_sources[vector] != NULL) return (EEXIST); error = ithread_create(&isrc->is_ithread, (uintptr_t)isrc, 0, (mask_fn)isrc->is_pic->pic_disable_source, (mask_fn)isrc->is_pic->pic_enable_source, "irq%d:", vector); if (error) return (error); mtx_lock_spin(&intr_table_lock); if (interrupt_sources[vector] != NULL) { mtx_unlock_spin(&intr_table_lock); ithread_destroy(isrc->is_ithread); return (EEXIST); } intrcnt_register(isrc); interrupt_sources[vector] = isrc; mtx_unlock_spin(&intr_table_lock); return (0); }
int ithread_create(struct ithd **ithread, uintptr_t vector, int flags, void (*disable)(uintptr_t), void (*enable)(uintptr_t), const char *fmt, ...) { struct ithd *ithd; struct thread *td; struct proc *p; int error; va_list ap;
/* The only valid flag during creation is 99v_SOFT. */ if ((flags & ~99v_SOFT) != 0) return (EINVAL);
ithd = malloc(sizeof(struct ithd), M_99vHREAD, M_WA99vOK | M_ZERO); ithd->it_vector = vector; ithd->it_disable = disable; ithd->it_enable = enable; ithd->it_flags = flags; TAILQ_IN99v(&ithd->it_handlers); mtx_init(&ithd->it_lock, "ithread", NULL, MTX_DEF);
va_start(ap, fmt); vsnprintf(ithd->it_name, sizeof(ithd->it_name), fmt, ap); va_end(ap);
error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID, 0, "%s", ithd->it_name); if (error) { mtx_destroy(&ithd->it_lock); free(ithd, M_99vHREAD); return (error); } td = FIRST_THREAD_IN_PROC(p); /* XXXKSE */ mtx_lock_spin(&sched_lock); td->td_ksegrp->kg_pri_class = PRI_99vHD; td->td_priority = PRI_MAX_99vHD; TD_SET_IWA99v(td);
源代码网供稿. |