⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 irq_smp.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
字号:
/* *	linux/arch/alpha/kernel/irq_smp.c * */#include <linux/kernel.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/random.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/irq.h>#include <asm/system.h>#include <asm/io.h>/* Who has global_irq_lock. */int global_irq_holder = NO_PROC_ID;/* This protects IRQ's. */spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;/* Global IRQ locking depth. */static void *previous_irqholder = NULL;#define MAXCOUNT 100000000static voidshow(char * str, void *where){#if 0	int i;        unsigned long *stack;#endif        int cpu = smp_processor_id();        printk("\n%s, CPU %d: %p\n", str, cpu, where);        printk("irq:  %d [%d %d]\n",	       irqs_running(),               local_irq_count(0),               local_irq_count(1));        printk("bh:   %d [%d %d]\n",	       spin_is_locked(&global_bh_lock) ? 1 : 0,	       local_bh_count(0),	       local_bh_count(1));#if 0        stack = (unsigned long *) &str;        for (i = 40; i ; i--) {		unsigned long x = *++stack;                if (x > (unsigned long) &init_task_union &&		    x < (unsigned long) &vsprintf) {			printk("<[%08lx]> ", x);                }        }#endif}static inline voidwait_on_irq(int cpu, void *where){	int count = MAXCOUNT;	for (;;) {		/*		 * Wait until all interrupts are gone. Wait		 * for bottom half handlers unless we're		 * already executing in one..		 */		if (!irqs_running()) {			if (local_bh_count(cpu)			    || !spin_is_locked(&global_bh_lock))				break;		}		/* Duh, we have to loop. Release the lock to avoid deadlocks */		spin_unlock(&global_irq_lock);		for (;;) {			if (!--count) {				show("wait_on_irq", where);				count = MAXCOUNT;			}			__sti();			udelay(1); /* make sure to run pending irqs */			__cli();			if (irqs_running())				continue;			if (spin_is_locked(&global_irq_lock))				continue;			if (!local_bh_count(cpu)			    && spin_is_locked(&global_bh_lock))				continue;			if (spin_trylock(&global_irq_lock))				break;		}	}}static inline voidget_irqlock(int cpu, void* where){	if (!spin_trylock(&global_irq_lock)) {		/* Do we already hold the lock?  */		if (cpu == global_irq_holder)			return;		/* Uhhuh.. Somebody else got it.  Wait.  */		spin_lock(&global_irq_lock);	}	/*	 * Ok, we got the lock bit.	 * But that's actually just the easy part.. Now	 * we need to make sure that nobody else is running	 * in an interrupt context. 	 */	wait_on_irq(cpu, where);	/*	 * Finally.	 */#if DEBUG_SPINLOCK	global_irq_lock.task = current;	global_irq_lock.previous = where;#endif	global_irq_holder = cpu;	previous_irqholder = where;}void__global_cli(void){	int cpu = smp_processor_id();	void *where = __builtin_return_address(0);	/*	 * Maximize ipl.  If ipl was previously 0 and if this thread	 * is not in an irq, then take global_irq_lock.	 */	if (swpipl(IPL_MAX) == IPL_MIN && !local_irq_count(cpu))		get_irqlock(cpu, where);}void__global_sti(void){        int cpu = smp_processor_id();        if (!local_irq_count(cpu))		release_irqlock(cpu);	__sti();}/* * SMP flags value to restore to: * 0 - global cli * 1 - global sti * 2 - local cli * 3 - local sti */unsigned long__global_save_flags(void){        int retval;        int local_enabled;        unsigned long flags;	int cpu = smp_processor_id();        __save_flags(flags);        local_enabled = (!(flags & 7));        /* default to local */        retval = 2 + local_enabled;        /* Check for global flags if we're not in an interrupt.  */        if (!local_irq_count(cpu)) {                if (local_enabled)                        retval = 1;                if (global_irq_holder == cpu)                        retval = 0;	}	return retval;}void__global_restore_flags(unsigned long flags){        switch (flags) {        case 0:                __global_cli();                break;        case 1:                __global_sti();                break;        case 2:                __cli();                break;        case 3:                __sti();                break;        default:                printk(KERN_ERR "global_restore_flags: %08lx (%p)\n",                        flags, __builtin_return_address(0));        }}/* * From its use, I infer that synchronize_irq() stalls a thread until * the effects of a command to an external device are known to have * taken hold.  Typically, the command is to stop sending interrupts. * The strategy here is wait until there is at most one processor * (this one) in an irq.  The memory barrier serializes the write to * the device and the subsequent accesses of global_irq_count. * --jmartin */#define DEBUG_SYNCHRONIZE_IRQ 0voidsynchronize_irq(void){#if 0	/* Joe's version.  */	int cpu = smp_processor_id();	int local_count;	int global_count;	int countdown = 1<<24;	void *where = __builtin_return_address(0);	mb();	do {		local_count = local_irq_count(cpu);		global_count = atomic_read(&global_irq_count);		if (DEBUG_SYNCHRONIZE_IRQ && (--countdown == 0)) {			printk("%d:%d/%d\n", cpu, local_count, global_count);			show("synchronize_irq", where);			break;		}	} while (global_count != local_count);#else	/* Jay's version.  */	if (irqs_running()) {		cli();		sti();	}#endif}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -