中断

中断是外围设备通知处理器的一种机制。

1. 中断控制器

外围设备不是把中断请求直接发送给处理器,而是发给中断控制器,由中断控制器转发给处理器。

不同种类的中断控制器的访问方法存在差异,为了屏蔽差异,内核定义了中断控制器描述符irq_chip,每种中断控制器自定义各种操作函数。GIC v2控制器的描述符如下:

drivers/irqchip/irq-gic.ctatic const struct irq_chip gic_chip = {.irq_mask		= gic_mask_irq,.irq_unmask		= gic_unmask_irq,.irq_eoi		= gic_eoi_irq,.irq_set_type		= gic_set_type,.irq_get_irqchip_state	= gic_irq_get_irqchip_state,.irq_set_irqchip_state	= gic_irq_set_irqchip_state,.flags			= IRQCHIP_SET_TYPE_MASKED |IRQCHIP_SKIP_SET_WAKE |IRQCHIP_MASK_ON_SUSPEND,
};

2. 中断域

一个大型系统可能有多个中断控制器,这些中断控制器可以级联,一个中断控制器作为中断源连接到另一个中断控制器,但只有一个中断控制器作为根控制器直接连接到处理器。为了把每个中断控制器本地的硬件中断映射到全局唯一的Linux中断号(也称为虚拟中断),内核定义了中断域irq_domain,每个中断控制器由自己的中断域。

2.1. 创建中断域

中断控制器的驱动程序使用分配函数irq_domain_add_*()创建和注册中断域。

2.2. 创建映射

创建中断域以后,需要向中断域添加硬件中断号到Linux中断号的映射,内核提供了函数irq_create_mapping:

unsigned int irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq);

输入参数是中断域和硬件中断号,返回Linux中断号。

该函数首先分配Linux中断号,然后把硬件中断号到Linux中断号的映射添加到中断域。

2.3. 查找映射

中断处理程序需要根据硬件中断号查找Linux中断号,内核提供了函数irq_find_mapping:

unsigned int irq_find_mapping(struct irq_domain *host, irq_hw_number_t hwirq);

输入参数是中断域和硬件中断号,返回Linux中断号。

3. 中断控制器驱动初始化

3.1. 设备树源文件

ARM64架构使用扁平设备树(Flattened Device Tree,FDT)描述板卡的硬件信息,好处是可以把板卡的特定的代码从内核中删除,编译生成通用的板卡无关的内核。

设备树源文件是文本文件,扩展名是“.dts”,需要在设备树源文件中描述中断的相关信息:

(1)中断控制器的信息

(2)对于作为中断源的外围设备,需要描述设备连接到哪个中断控制器,使用哪个硬件中断号

参考arch/arm64/boot/dts/arm/foundation-v8.dtsi、arch/arm64/boot/dts/arm/foundation-v8-gicv2.dtsi。

3.2. 中断控制器匹配表

在GIC v2控制器的驱动程序中,定义了多个类型为of_device_id的静态变量,成员compatible是驱动程序支持的设备的名称,成员data是初始化函数,编译器把这些静态变量放在专用的节“__irqchip_of_table”里面。

我们把节“__irqchip_of_table”称为中断控制器匹配表,里面每个表项的格式是结构体of_device_id。

drivers/irqchip/irq-gic.cIRQCHIP_DECLARE(gic_400, "arm,gic-400", gic_of_init);
...
IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init);
IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
...

把宏IRQCHIP_DECLARE展开以后是:

static const struct of_device_id __of_table_cortex_gic_400__section(__irqchip_of_table)= { .compatible = "arm,gic-g400",	.data = gic_of_init  }
...
static const struct of_device_id __of_table_cortex_a15_gic__section(__irqchip_of_table)= { .compatible = "arm,cortex-a15-gic",	.data = gic_of_init  }
static const struct of_device_id __of_table_cortex_a9_gic__section(__irqchip_of_table)= { .compatible = "arm,cortex-a9-gic",	.data = gic_of_init  }
...

3.3. 初始化

在内核初始化的时候,匹配设备树文件中的中断控制器的属性“compatible”和内核的中断控制器匹配表,找到合适的中断控制器驱动程序,执行驱动程序的初始化函数。

start_kernel()  ->  init_IRQ()  ->  irqchip_init()drivers/irqchip/irqchip.c
void __init irqchip_init(void)
{of_irq_init(__irqchip_of_table);    // 参数是中断控制器匹配表的起始地址__irqchip_of_table...
}

(1)函数of_irq_init

driver/of/irq.c
/*** of_irq_init - Scan and init matching interrupt controllers in DT* @matches: 0 terminated array of nodes to match and init function to call** This function scans the device tree for matching interrupt controller nodes,* and calls their initialization functions in order with parents first.*/
void __init of_irq_init(const struct of_device_id *matches)
{const struct of_device_id *match;struct device_node *np, *parent = NULL;struct of_intc_desc *desc, *temp_desc;struct list_head intc_desc_list, intc_parent_list;INIT_LIST_HEAD(&intc_desc_list);INIT_LIST_HEAD(&intc_parent_list);for_each_matching_node_and_match(np, matches, &match) {		/* 遍历设备树文件的设备节点。如果属性compatible和中断控制器匹配表中的任何一条表项的字段compatible匹配,处理如下 */if (!of_property_read_bool(np, "interrupt-controller") ||!of_device_is_available(np))		/* 如果没有节点属性interrupt-controller,说明设备不是中断控制器,忽略该设备 */continue;if (WARN(!match->data, "of_irq_init: no init function for %s\n",match->compatible))continue;/** Here, we allocate and populate an of_intc_desc with the node* pointer, interrupt-parent device_node etc.*/desc = kzalloc(sizeof(*desc), GFP_KERNEL);		/* 分配一个of_intc_desc实例 */if (WARN_ON(!desc)) {of_node_put(np);goto err;}desc->irq_init_cb = match->data;		/* 成员irq_init_cb保存初始化函数 */desc->dev = of_node_get(np);		/* 成员dev保存本设备的device_node */desc->interrupt_parent = of_irq_find_parent(np);		/* 成员interrupt保存父设备 */if (desc->interrupt_parent == np)desc->interrupt_parent = NULL;list_add_tail(&desc->list, &intc_desc_list);		/* 把of_intc_desc实例添加到链表intc_desc_list中 */}/** The root irq controller is the one without an interrupt-parent.* That one goes first, followed by the controllers that reference it,* followed by the ones that reference the 2nd level controllers, etc.*/while (!list_empty(&intc_desc_list)) {		/* 遍历链表intc_desc_list,从根设备开始,先执行父设备的初始化函数,然后执行子设备的初始化函数 *//** Process all controllers with the current 'parent'.* First pass will be looking for NULL as the parent.* The assumption is that NULL parent means a root controller.*/list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {int ret;if (desc->interrupt_parent != parent)continue;list_del(&desc->list);of_node_set_flag(desc->dev, OF_POPULATED);pr_debug("of_irq_init: init %pOF (%p), parent %p\n",desc->dev,desc->dev, desc->interrupt_parent);ret = desc->irq_init_cb(desc->dev,desc->interrupt_parent);if (ret) {of_node_clear_flag(desc->dev, OF_POPULATED);kfree(desc);continue;}/** This one is now set up; add it to the parent list so* its children can get processed in a subsequent pass.*/list_add_tail(&desc->list, &intc_parent_list);}/* Get the next pending parent that might have children */desc = list_first_entry_or_null(&intc_parent_list,typeof(*desc), list);if (!desc) {pr_err("of_irq_init: children remain, but no parents\n");break;}list_del(&desc->list);parent = desc->dev;kfree(desc);}list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {list_del(&desc->list);kfree(desc);}
err:list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {list_del(&desc->list);of_node_put(desc->dev);kfree(desc);}
}

设备树文件“arch/arm64/boot/dts/arm/foundation-v8.dts”里面中断控制器的属性“compatible”是:

compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";

和中断控制器匹配表中的

{ .compatible = "arm,cortex-a15-gic", .data = gic_of_init  }
{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init  }

匹配。

(2)gic_of_init

int __init
gic_of_init(struct device_node *node, struct device_node *parent)			/* 参数node是本中断控制器,参数parent是父设备 */
{struct gic_chip_data *gic;int irq, ret;if (WARN_ON(!node))return -ENODEV;if (WARN_ON(gic_cnt >= CONFIG_ARM_GIC_MAX_NR))return -EINVAL;gic = &gic_data[gic_cnt];		/* 从全局数组gic_data取一个空闲的元素来保存本中断控制器的信息 */ret = gic_of_setup(gic, node);		/* 调用函数gic_of_setup:从设备树文件读取中断控制器的属性reg,获取分发器和处理器接口的寄存器的物理地址范围,把物理地址映射到内核的虚拟地址空间 */if (ret)return ret;/** Disable split EOI/Deactivate if either HYP is not available* or the CPU interface is too small.*/if (gic_cnt == 0 && !gic_check_eoimode(node, &gic->raw_cpu_base))static_branch_disable(&supports_deactivate_key);ret = __gic_init_bases(gic, -1, &node->fwnode);		/* 调用函数__gic_init_bases以初始化结构体gic_chip_data */if (ret) {gic_teardown(gic);return ret;}if (!gic_cnt) {gic_init_physaddr(node);gic_of_setup_kvm_info(node);}if (parent) {		/* 如果本中断控制器有父设备,即作为中断源连接到其他中断控制器,处理如下 */irq = irq_of_parse_and_map(node, 0);		/* 调用函数irq_of_parse_and_map:从设备树文件中本设备节点的属性interrupts获取硬件中断号,把硬件中断号映射到Linux中断号n */gic_cascade_irq(gic_cnt, irq);		/* 调用函数gic_cascade_irq:把Linux中断号n中断描述符的成员handle_irq()设置为函数gic_handle_cascade_irq() */}if (IS_ENABLED(CONFIG_ARM_GIC_V2M))gicv2m_init(&node->fwnode, gic_data[gic_cnt].domain);gic_cnt++;return 0;
}

(3)函数__gic_init_bases

static int __init __gic_init_bases(struct gic_chip_data *gic,int irq_start,struct fwnode_handle *handle)
{char *name;int i, ret;if (WARN_ON(!gic || gic->domain))return -EINVAL;if (gic == &gic_data[0]) {		/* 如果本中断控制器是根控制器,处理如下: *//** Initialize the CPU interface map to all CPUs.* It will be refined as each CPU probes its ID.* This is only necessary for the primary GIC.*/for (i = 0; i < NR_GIC_CPU_IF; i++)gic_cpu_map[i] = 0xff;
#ifdef CONFIG_SMPset_smp_cross_call(gic_raise_softirq);		/* 把全局函数指针__smp_cross_call设置为函数gic_raise_softirq */
#endif											/* 用来发送软件生成的中断,即一个处理器向其他处理器发送中断 */cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING,"irqchip/arm/gic:starting",gic_starting_cpu, NULL);set_handle_irq(gic_handle_irq);		/* 把全局函数指针handle_arch_irq设置为函数gic_handle_irq,该函数是中断处理程序C语言部分的入口 */if (static_branch_likely(&supports_deactivate_key))pr_info("GIC: Using split EOI/Deactivate mode\n");}/* 调用函数gic_init_chip以初始化中断控制器描述符irq_chip */if (static_branch_likely(&supports_deactivate_key) && gic == &gic_data[0]) {name = kasprintf(GFP_KERNEL, "GICv2");gic_init_chip(gic, NULL, name, true);} else {name = kasprintf(GFP_KERNEL, "GIC-%d", (int)(gic-&gic_data[0]));gic_init_chip(gic, NULL, name, false);}ret = gic_init_bases(gic, irq_start, handle);		/* 调用函数gic_init_bases进行初始化:为本中断控制器分配中断域,初始化中断控制器的分发器的各种寄存器,初始化中断控制器的处理器接口的各种寄存器 */if (ret)kfree(name);return ret;
}

4. Linux中断处理

对于中断控制器的每个中断源,向中断域添加硬件中断号到Linux中断号的映射时,内核分配一个Linux中断号和一个中断描述符irq_desc,中断描述符由两个层次的中断处理函数:

(1)第一层处理函数是中断描述符的成员handle_irq()

(2)第二层处理函数是设备驱动程序注册的处理函数。中断描述符由一个中断处理链表(irq_desc.action),每个中断处理描述符(irq_action)保存设备驱动程序注册的处理函数。因为多个设备可以共享同一个硬件中断号,所以中断处理链表可能挂载多个中断处理描述符。

怎么存储Linux中断号到中断描述符的映射关系?

有两种实现方式:

(1)如果中断编号是稀疏的(即不连续),那么使用基数树(radix tree)存储。需要开启配置宏CONFIG_SPARSE_IRQ。

(2)如果中断编号是连续的,那么使用数组存储。

#ifdef CONFIG_SPARSE_IRQ...
static RADIX_TREE(irq_desc_tree, GFP_KERNEL);
...#else /* !CONFIG_SPARSE_IRQ */struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {[0 ... NR_IRQS-1] = {.handle_irq	= handle_bad_irq,.depth		= 1,.lock		= __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),}
};
...#endif /* !CONFIG_SPARSE_IRQ */

把硬件中断号映射到Linux中断号的时候,根据硬件中断的类型设置中断描述符的成员handle_irq(),以GIC v2控制器为例,函数gic_irq_domain_map所做的处理如下:

irq_create_mapping  ->  irq_domain_associate()  ->  domain->ops->map()  ->  gic_irq_domain_map()drivers/irqchip/irq-gic.c
tatic int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,irq_hw_number_t hw)
{struct gic_chip_data *gic = d->host_data;if (hw < 32) {		/* 如果硬件中断号小于32,说明是软件生成的中断或私有外设中断,那么把终端描述符的成员handle_irq()设置为函数handle_percpu_devid_irq */irq_set_percpu_devid(irq);irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,handle_percpu_devid_irq, NULL, NULL);irq_set_status_flags(irq, IRQ_NOAUTOEN);} else {		/* 如果硬件中断号大于或等于32,说明共享外设中断,那么把中断描述符的成员handle_irq()设置为函数handle_fasteoi_irq */irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,handle_fasteoi_irq, NULL, NULL);irq_set_probe(irq);irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq)));}return 0;
}

在ARM64架构下,在异常级别1的异常向量表中,中断的入口有3个:

(1)如果处理器处在内核模式(异常级别1),中断的入口是el1_irq;

(2)如果处理器正在用户模式(异常级别0)下执行64位应用程序,中断的入口是el0_irq;

(3)如果处理器正在用户模式(异常级别0)下执行32位应用程序,中断的入口是el0_irq_compat。

假设处理器正在用户模式(异常级别0)下执行64位应用程序,中断控制器是GIC v2控制器,Linux中断处理流程如下:

 

函数el0_irq的代码如下:

arch/arm64/kernel/irq.c
/* 每个处理器有一个专用的中断栈 */
DEFINE_PER_CPU(unsigned long *, irq_stack_ptr);arch/arm64/kernel/entry.S
/** Interrupt handling.*/.macro	irq_handlerldr_l	x1, handle_arch_irqmov	x0, spirq_stack_entry		// 从进程的内核栈切换到中断栈blr	x1		// 调用函数指针handle_arch_irq指向的函数irq_stack_exit		// 从中断栈切换到进程的内核栈.endm.align	6
el1_irq:kernel_entry 1enable_da_f
#ifdef CONFIG_TRACE_IRQFLAGSbl	trace_hardirqs_off
#endifirq_handler            // irq_handler是一个宏#ifdef CONFIG_PREEMPTldr	x24, [tsk, #TSK_TI_PREEMPT]	// get preempt count	读取抢占计数cbnz	x24, 1f				// preempt count != 0		抢占计数不等于0bl	el1_preempt
1:
#endif
#ifdef CONFIG_TRACE_IRQFLAGSbl	trace_hardirqs_on
#endifkernel_exit 1
ENDPROC(el1_irq)

在gic_of_init()  ->  __gic_init_bases中初始化了函数handle_arch_irq,GIC v2控制器把该函数指针设置为函数gic_handle_irq。

drivers/irqchip/irq-gic.c
static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{u32 irqstat, irqnr;struct gic_chip_data *gic = &gic_data[0];void __iomem *cpu_base = gic_data_cpu_base(gic);do {irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);		/* 读取处理器接口的中断确认寄存器得到中断号 */irqnr = irqstat & GICC_IAR_INT_ID_MASK;if (likely(irqnr > 15 && irqnr < 1020)) {		/* 如果硬件中断号大于15且小于1020,即中断是由外围设备发送的 */if (static_branch_likely(&supports_deactivate_key))		/* 把中断号写到处理器接口的中断结束寄存器中,指示中断处理完成 */writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);		isb();handle_domain_irq(gic->domain, irqnr, regs);		/* 如果是私有外设中断,那么中断描述符的成员handle_irq()是函数handle_percpu_devid_irq; */continue;					        /* 如果是共享外设中断,那么中断描述符的成员handle_irq()是函数handle_fasteoi_irq */}if (irqnr < 16) {		/* 如果硬件中断号小于16,即软件生成的中断 */writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);if (static_branch_likely(&supports_deactivate_key))		/* 把中断号写到处理器接口的中断结束寄存器中,指示中断处理完成 */writel_relaxed(irqstat, cpu_base + GIC_CPU_DEACTIVATE);
#ifdef CONFIG_SMP/** Ensure any shared data written by the CPU sending* the IPI is read after we've read the ACK register* on the GIC.** Pairs with the write barrier in gic_raise_softirq*/smp_rmb();handle_IPI(irqnr, regs);
#endifcontinue;}break;} while (1);
}

函数handle_domain_irq():

include/linux/irqdesc.h
static inline void generic_handle_irq_desc(struct irq_desc *desc)
{desc->handle_irq(desc);
}kernel/irq/irqdesc.c
int generic_handle_irq(unsigned int irq)
{struct irq_desc *desc = irq_to_desc(irq);if (!desc)return -EINVAL;generic_handle_irq_desc(desc);return 0;
}kernel/irq/irqdesc.c
#ifdef CONFIG_HANDLE_DOMAIN_IRQ
int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,bool lookup, struct pt_regs *regs)
{struct pt_regs *old_regs = set_irq_regs(regs);unsigned int irq = hwirq;int ret = 0;irq_enter();#ifdef CONFIG_IRQ_DOMAINif (lookup)irq = irq_find_mapping(domain, hwirq);
#endif/** Some hardware gives randomly wrong interrupts.  Rather* than crashing, do something sensible.*/if (unlikely(!irq || irq >= nr_irqs)) {ack_bad_irq(irq);ret = -EINVAL;} else {generic_handle_irq(irq);}irq_exit();set_irq_regs(old_regs);return ret;
}
#endifinclude/linux/irqdesc.h
static inline int handle_domain_irq(struct irq_domain *domain,unsigned int hwirq, struct pt_regs *regs)
{return __handle_domain_irq(domain, hwirq, true, regs);
}

如果是私有外设中断,那么中断描述符的成员handle_irq()是函数handle_percpu_devid_irq,其代码如下:

kernel/irq/chip.c
void handle_percpu_devid_irq(struct irq_desc *desc)
{struct irq_chip *chip = irq_desc_get_chip(desc);struct irqaction *action = desc->action;unsigned int irq = irq_desc_get_irq(desc);irqreturn_t res;...if (chip->irq_ack)chip->irq_ack(&desc->irq_data);if (likely(action)) {...res = action->handler(irq, raw_cpu_ptr(action->percpu_dev_id));...} else {...}if (chip->irq_eoi)chip->irq_eoi(&desc->irq_data);
}

如果是共享外设中断,那么中断描述符的成员handle_irq()是函数handle_fasteoi_irq,其代码如下:

kernel/irq/chip.c
void handle_fasteoi_irq(struct irq_desc *desc)
{struct irq_chip *chip = desc->irq_data.chip;raw_spin_lock(&desc->lock);if (!irq_may_run(desc))goto out;desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);/** If its disabled or no action available* then mask it and get out of here:*/if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {desc->istate |= IRQS_PENDING;mask_irq(desc);goto out;}kstat_incr_irqs_this_cpu(desc);if (desc->istate & IRQS_ONESHOT)mask_irq(desc);preflow_handler(desc);handle_irq_event(desc);		/* 调用函数handle_irq_event执行设备驱动程序注册的处理函数 */cond_unmask_eoi_irq(desc, chip);raw_spin_unlock(&desc->lock);return;
out:if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED))chip->irq_eoi(&desc->irq_data);raw_spin_unlock(&desc->lock);
}

函数handle_irq_event把主要工作委托给函数__handle_irq_event_percpu。函数__handle_irq_event_percpu遍历中断描述符的中断处理链表,执行每个中断处理描述符的处理函数,其代码如下:

handle_irq_event()  ->  handle_irq_event_percpu()  ->  __handle_irq_event_percpu()kernel/irq/handle.c
irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
{irqreturn_t retval = IRQ_NONE;unsigned int irq = desc->irq_data.irq;struct irqaction *action;/* 遍历中断描述符的的中断处理链表,执行每个中断处理描述符的处理函数 */record_irq_time(desc);for_each_action_of_desc(desc, action) {		irqreturn_t res;trace_irq_handler_entry(irq, action);res = action->handler(irq, action->dev_id);trace_irq_handler_exit(irq, action, res);if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",irq, action->handler))local_irq_disable();switch (res) {case IRQ_WAKE_THREAD:/** Catch drivers which return WAKE_THREAD but* did not set up a thread function*/if (unlikely(!action->thread_fn)) {warn_no_thread(irq, action);break;}__irq_wake_thread(desc, action);/* 继续往下走,把action->flags作为生成随机数的一个因子 *//* Fall through to add to randomness */case IRQ_HANDLED:*flags |= action->flags;break;default:break;}retval |= res;}return retval;
}

5. 中断线程化

中断线程化就是使用内核线程处理中断,目的是减少系统关中断的时间,增强系统的实时性。内核提供的函数request_threaded_irq()用来注册线程化的中断:

int request_threaded_irq(unsigned int irq, irq_handler_t handler,irq_handler_t thread_fn, unsigned long irqflags,const char *devname, void *dev_id)

参数thread_fn是线程处理函数。

少数中断不能线程化,典型的例子是时钟中断,有些流氓进程不主动让出处理器,内核只能依靠周期性的时钟中断夺回处理器的控制权,时钟中断是调度器的脉搏。对于不能线程化的中断,注册处理函数的时候必须设置标志IRQF_NO_THREAD。

如果开启了强制中断线程化的配置宏CONFIG_IRQ_FORCED_THREADING,并且在引导内核的时候指定内核参数“threadirqs”,那么强制除了标记IRQF_NO_THREAD以外的所有中断线程化。

每个中断描述符(irqaction)对应一个内核线程,其代码如下:

include/linux/interrupt.h
struct irqaction {irq_handler_t		handler;void			*dev_id;void __percpu		*percpu_dev_id;struct irqaction	*next;		/* 中断处理描述符链表 */irq_handler_t		thread_fn;		/* 指向线程处理函数 */struct task_struct	*thread;		/* 指向内核线程的进程描述符 */struct irqaction	*secondary;unsigned int		irq;unsigned int		flags;unsigned long		thread_flags;unsigned long		thread_mask;const char		*name;struct proc_dir_entry	*dir;
} ____cacheline_internodealigned_in_smp;

 

request_threaded_irq()  ->  __setup_irq()  ->  setup_irq_thread()kernel/irq/manage.c
static int
setup_irq_thread(struct irqaction *new, unsigned int irq, bool secondary)
{struct task_struct *t;struct sched_param param = {.sched_priority = MAX_USER_RT_PRIO/2,		/*  */};if (!secondary) {t = kthread_create(irq_thread, new, "irq/%d-%s", irq,new->name);		/* 名称是“irq/”后面跟着Linux中断号,线程处理函数是irq_thread() */} else {t = kthread_create(irq_thread, new, "irq/%d-s-%s", irq,new->name);param.sched_priority -= 1;}if (IS_ERR(t))return PTR_ERR(t);sched_setscheduler_nocheck(t, SCHED_FIFO, &param);		/* 中断处理线程是优先级为50、调度策略是SCHED_FIFO的实时内核线程 *//** We keep the reference to the task struct even if* the thread dies to avoid that the interrupt code* references an already freed task_struct.*/get_task_struct(t);new->thread = t;/** Tell the thread to set its affinity. This is* important for shared interrupt handlers as we do* not invoke setup_affinity() for the secondary* handlers as everything is already set up. Even for* interrupts marked with IRQF_NO_BALANCE this is* correct as we want the thread to move to the cpu(s)* on which the requesting code placed the interrupt.*/set_bit(IRQTF_AFFINITY, &new->thread_flags);return 0;
}

在中断处理程序中,函数__handle_irq_event_percpu遍历中断描述符的中断处理链表,执行每个中断处理描述符的处理函数。如果返回IRQ_WAKE_THREAD,说明是线程化的中断,那么唤醒中断处理线程。

中断处理线程的处理函数是irq_thread(),调用函数irq_thread_fn(),然后函数irq_thread_fn()调用注册的线程处理函数。

kernel/irq/manage.cstatic irqreturn_t irq_thread_fn(struct irq_desc *desc,struct irqaction *action)
{irqreturn_t ret;ret = action->thread_fn(action->irq, action->dev_id);if (ret == IRQ_HANDLED)atomic_inc(&desc->threads_handled);irq_finalize_oneshot(desc, action);return ret;
}static int irq_thread(void *data)
{struct callback_head on_exit_work;struct irqaction *action = data;struct irq_desc *desc = irq_to_desc(action->irq);irqreturn_t (*handler_fn)(struct irq_desc *desc,struct irqaction *action);if (force_irqthreads && test_bit(IRQTF_FORCED_THREAD,&action->thread_flags))handler_fn = irq_forced_thread_fn;elsehandler_fn = irq_thread_fn;init_task_work(&on_exit_work, irq_thread_dtor);task_work_add(current, &on_exit_work, false);irq_thread_check_affinity(desc, action);while (!irq_wait_for_interrupt(action)) {irqreturn_t action_ret;irq_thread_check_affinity(desc, action);action_ret = handler_fn(desc, action);if (action_ret == IRQ_WAKE_THREAD)irq_wake_secondary(desc, action);wake_threads_waitq(desc);}/** This is the regular exit path. __free_irq() is stopping the* thread via kthread_stop() after calling* synchronize_hardirq(). So neither IRQTF_RUNTHREAD nor the* oneshot mask bit can be set.*/task_work_cancel(current, irq_thread_dtor);return 0;
}

6. 禁止/开启中断

禁止中断接口:

(1)local_irq_disable()

(2)local_irq_save(flags):首先把中断状态保存在参数flags中,然后禁止中断

这两个接口只能禁止本处理器的中断,不能禁止其他处理器的中断。

开启中断接口:

(1)local_irq_enable()

(2)local_irq_restore(flags):恢复本处理器的中断状态

local_irq_disable()和local_irq_enable()不能嵌套使用,local_irq_save(flags)和local_irq_restore(flags)可以嵌套使用。

7. 禁止/开启单个中断

禁止中断的函数是:void disable_irq(unsigned int irq),参数irq是Linux中断号

开启中断的函数是:void enable_irq(unsigned int irq),参数irq是Linux中断号

8. 中断亲和性

在多处理器系统中,管理员可以设置中断亲和性,允许中断控制器把某个中断转发给哪些处理器,有两种配置方法:

(1)写文件“/proc/irq/IRQ#/smp_affinity”,参数是位掩码

(2)写文件“/proc/irq/IRQ#/smp_affinity_list”,参数是处理器列表

内核提供了设置中断亲和性的函数:

int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)

参数irq是Linux中断号,参数cpumask是处理器位掩码。

9. 处理器间中断

处理器间中断(Inter-Processor Interrupt,IPI)是一种特殊的中断,在多处理器系统中,一个处理器可以向其他处理器发送中断,要求目标处理器执行某件事情。

常见的使用处理器间中断的函数如下:

(1)在所有处理器上执行同一个函数:

int up_smp_call_function(smp_call_func_t func, void *info, int wait);

(2)在指定的处理器上执行一个函数

int smp_call_function_single(int cpuid, smp_call_func_t func, void *info, int wait);

(3)要求指定的处理器重新调度进程

void smp_send_reschedule(int cpu);

对于ARM64架构的GIC控制器,把处理器间生成的中断称为软件生成的中断。

函数handle_IPI负责处理处理器减中断,参数ipinr是硬件中断号,其代码如下:

arch/arm64/kernel/smp.c
void handle_IPI(int ipinr, struct pt_regs *regs)
{unsigned int cpu = smp_processor_id();struct pt_regs *old_regs = set_irq_regs(regs);if ((unsigned)ipinr < NR_IPI) {trace_ipi_entry_rcuidle(ipi_types[ipinr]);__inc_irq_stat(cpu, ipi_irqs[ipinr]);}/* 目前支持7种处理间中断 */switch (ipinr) {case IPI_RESCHEDULE:		/* 硬件中断号是0,重新调度进程,函数smp_send_reschedule()生成的中断 */scheduler_ipi();break;case IPI_CALL_FUNC:		/* 硬件中断号是1,执行函数,函数smp_call_function生成的中断 */irq_enter();generic_smp_call_function_interrupt();irq_exit();break;case IPI_CPU_STOP:		/* 硬件中断号是2,使处理器停止,函数smp_send_stop()生成的中断 */irq_enter();ipi_cpu_stop(cpu);irq_exit();break;case IPI_CPU_CRASH_STOP:		/* 硬件中断号是3,使处理器停止,函数smp_send_crash_stop()生成的中断 */if (IS_ENABLED(CONFIG_KEXEC_CORE)) {irq_enter();ipi_cpu_crash_stop(cpu, regs);unreachable();}break;#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCASTcase IPI_TIMER:		/* 硬件中断号是4,广播的时钟事件,函数tick_broadcast()生成的中断 */irq_enter();tick_receive_broadcast();irq_exit();break;
#endif#ifdef CONFIG_IRQ_WORKcase IPI_IRQ_WORK:		/* 硬件中断号是5,在硬中断上下文中执行回调函数,函数irq_work_queue()生成的中断 */irq_enter();irq_work_run();irq_exit();break;
#endif#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOLcase IPI_WAKEUP:		/* 硬件中断号是6,唤醒处理器,函数acpi_parking_protocol_cpu_boot()生成的中断 */WARN_ONCE(!acpi_parking_protocol_valid(cpu),"CPU%u: Wake-up IPI outside the ACPI parking protocol\n",cpu);break;
#endifdefault:pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);break;}if ((unsigned)ipinr < NR_IPI)trace_ipi_exit_rcuidle(ipi_types[ipinr]);set_irq_regs(old_regs);
}
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 16.待写

    16.待写...

    2024/4/25 0:09:25
  2. 页面布局方式有哪些?

    静态布局: pc页面无论宽高是否发生改变,元素的布局方式都不会发生改变 双飞翼布局(圣杯布局): 左右固定,中间内容区域随着窗口变大而变大,缩小而缩小 100%布局: 屏幕尺寸越大,显示的内容越多(高度固定) Rem布局(等比缩放布局,弹性布局): 不同的尺寸,显示的内容大…...

    2024/4/25 0:09:22
  3. [PTA] 求组合数

    本题要求编写程序,根据公式C​n​m​​=​m!(n−m)!​​n!​​算出从n个不同元素中取出m个元素(m≤n)的组合数。建议定义和调用函数fact(n)计算n!,其中n的类型是int,函数类型是double。输入格式:输入在一行中给出两个正整数m和n(m≤n),以空格分隔。输出格式:按照格式“…...

    2024/4/25 0:09:20
  4. JNDI

    JNDI含义 JNDI是 Java命名与目录接口(Java Naming and Directory Interface) 是一个为Java应用程序提供命名服务的应用程序接口,为我们提供了查找和访问各种命名和目录服务的通用统一的接口.通过JNDI统一接口我们可以来访问各种不同类型的服务 JNDI可以把java应用程序访问数据库…...

    2024/4/25 0:09:19
  5. 开发常用快捷键

    开发常用快捷键IDEAVSVSCode浏览器 IDEA 复制当前行到下一行:CTRL+D 添入getset方法:Alt+Insert 快速创建主函数:PSVM 快速选中代码:CTRL+W 切换标签:Ctrl+Tab 下方插入一行空行:Shift+Enter 移动一行代码:Ctrl+Shift+↑/↓ 或者 Alt+Shift+↑/↓ 删除一行代码:Ctrl+…...

    2024/4/25 0:09:19
  6. ontextmenu事件

    简介它属于DOM元素事件 所有浏览器都支持ontextmenu事件详情点击 使用<body><div id="wrap"></div> </body>document.oncontextmenu=function(ev){ev = ev||event;var x = ev.clientX;var y = ev.clientY;var wrap =document.querySelector(…...

    2024/4/24 4:18:13
  7. 嵌入式计算机视觉开发

    嵌入式计算机视觉开发...

    2024/5/3 2:04:43
  8. 【剑指offer】序列化二叉树

    问题描述 请实现两个函数,分别用来序列化和反序列化二叉树 二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是…...

    2024/4/25 0:09:18
  9. Unity简单自定义窗口的创建(Unity3d / C#)

    在Assets里面创建一个Editor文件夹,创建一个新的 C# 脚本叫MyWindow(名字可以自己修改,对应代码也要修改),写入代码,点击unity界面的Window菜单栏,然后点击EditColor即可打开界面(可自行修改) 界面样式:代码: using UnityEngine; using UnityEditor;public class My…...

    2024/4/25 0:09:17
  10. Leetcode 437. Path Sum III (python+cpp)

    Leetcode 437. Path Sum III题目错误解法:正确解法: 题目错误解法: 这道题目坑爹的地方在于路径可以不从根节点开始。刚看到题目的时候天真的以为是从根节点开始,于是就有了下面的错误解法: class Solution:def pathSum(self, root: TreeNode, sum: int) -> int:self.c…...

    2024/4/25 0:09:13
  11. JAVA之对象的转型(向上自动转型、向下的强制转型、特殊转型int类型)

    ...

    2024/4/25 0:09:13
  12. HBASE LSM树 以及针对读操作的优化方式(多路归并(compact),布隆过滤器)

    LSM存储引擎是在B+树的基础上衍生过来的,目的就是为了在读和写之间,提高写的性能。所以,LSM树的弊端也由此可见,对读并不是很友好,所以,针对LSM树,有后续compact,布隆过滤器,blockCache等优化方式。来弥补对读的查询。LSM树的索引一般由2部分构成,一部分是内存部分,…...

    2024/4/14 20:46:57
  13. 局部搜索、模拟退火和遗传算法求解TSP问题

    模拟退火和遗传算法求解TSP问题 源代码传送门:GITHUB 数据传送门:TSPLIB 文章目录模拟退火和遗传算法求解TSP问题摘要1 导言1.1 问题重述1.2 TSP问题选择1.3 思路设计1.4 结果简览2 实验过程2.1 TSPbase2.2 LocalSearch2.2.1 流程图2.2.2 满意度、活跃度机制2.2.3 邻域操作2.…...

    2024/4/25 13:38:39
  14. C++ primer plus pre 4.6 chapter source code

    2.3.1. 使用cin 2.3.2. 使用cout进行拼接carrot();2.4.1. 函数sqrt();2.4.2. 函数变体pow();random1();2.4.3. 用户定义的函数cinNumFunc();2.4.4. 用户定义有返回值的函数userCustom();3.1.3. 整型short、int、long和long longshowClimit(); see_exceed();3.1.8. char 类型:…...

    2024/4/26 1:31:46
  15. C++双继承显示四不像的特点

    编者:李国帅qq:9611153 微信lgs9611153背景原因:翻看多年前的例子,觉得挺有意思。C++是不多见的支持多继承的语言了,这让我想起了四不像。大家端午节快乐!问题描述及期望效果:写了一个简单的小程序,打印出如下结果。/* 麋鹿 有马的头 麋鹿 有鹿的角 麋鹿 有牛的蹄 麋鹿 有…...

    2024/4/19 10:36:40
  16. Spring---学习第三天(Spring核心之IOC)

    Spring第三天AOP简介什么是AOP?AOP的作用以及优势作用优势引入学习案例----给业务层添加事务的支持AOP的相关术语Joinpoint(连接点)Pointcut(切入点)Advice(通知/增强)Introduction(引介)Target(目标对象)Weaving(织入)Proxy(代理)Aspect(切面)学习 spring 中的 AOP 要明确的…...

    2024/5/3 23:32:34
  17. java毕业设计_基于安卓的游戏玩家交流app的设计与实现

    基于安卓的游戏玩家交流app的设计与实现 基于安卓的游戏玩家交流app的设计与实现mysql数据库创建语句 基于安卓的游戏玩家交流app的设计与实现oracle数据库创建语句 基于安卓的游戏玩家交流app的设计与实现sqlserver数据库创建语句 基于安卓的游戏玩家交流app的设计与实现sprin…...

    2024/4/24 19:54:45
  18. 2020最新超星学习通军事理论自动刷课答题考试答案教程~亲测可用

    **可解除网页的各种限制,包含以下功能和军事理论考试答案自动播放视频,缩小不暂停 章节测试,考试自动答题 根据任务数,自动切换视频 模拟手动操作100%安全,亲测很稳!!!**首先我们从下面的链接中下载专用浏览器(软件来源于网络) 蓝奏云:https://afeixz.lanzous.com/b…...

    2024/5/3 4:52:23
  19. Vivado Could not open file xsim.dir/tb_XXXX_behav/xsim.mem for writing解决方案

    解决方法在任务管理器中将xsimk.exe进程结束即可,重新进行行为级仿真 参考链接...

    2024/4/25 0:09:08
  20. 全志V40 Android 修改默认输入法

    Settings.java frameworks/base/core/java/android/provider/Settings.java 中定义public static final String DEFAULT_INPUT_METHOD = "default_input_method";DatabaseHelper.java frameworks/base/packages/SettingsProvider/src/com/android/providers/settings…...

    2024/5/4 10:24:34

最新文章

  1. springboot整合mybatis配置多数据源(mysql/oracle)

    目录 前言导入依赖坐标创建mysql/oracle数据源配置类MySQLDataSourceConfigOracleDataSourceConfig application.yml配置文件配置mysql/oracle数据源编写Mapper接口编写Book实体类编写测试类 前言 springboot整合mybatis配置多数据源&#xff0c;可以都是mysql数据源&#xff…...

    2024/5/4 14:47:17
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. C# 构建可定时关闭的异步提示弹窗

    C# 构建可定时关闭的异步提示弹窗 引言1、调用接口的实现2、自动定时窗口的实现 引言 我们在最常用最简单的提示弹框莫过于MessageBox.Show( )的方法了&#xff0c;但是使用久了之后&#xff0c;你会发现这个MessageBox并不是万能的&#xff0c;有事后并不想客户去点击&#x…...

    2024/5/3 5:57:39
  4. 【LeetCode热题100】【二叉树】二叉树的中序遍历

    题目链接&#xff1a;94. 二叉树的中序遍历 - 力扣&#xff08;LeetCode&#xff09; 中序遍历就是先遍历左子树再遍历根最后遍历右子树 class Solution { public:void traverse(TreeNode *root) {if (!root)return;traverse(root->left);ans.push_back(root->val);tra…...

    2024/5/3 21:52:01
  5. WP Rocket v3.15.10最新版强大的WordPress缓存插件

    WP Rocket v3.15.10是一款强大的WordPress缓存插件&#xff0c;它通过一系列优化措施来提高网站的速度和性能。 WP Rocket与免费缓存插件相比&#xff0c;提供了更丰富和高级的自定义设置功能。这些包括媒体优化、预加载、延迟加载和数据库优化等。特别是对于没有任何缓存技术…...

    2024/5/4 5:52:31
  6. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/1 17:30:59
  7. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/2 16:16:39
  8. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  9. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/3 23:10:03
  10. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  11. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  12. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  13. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  14. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  15. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/2 15:04:34
  16. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  17. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  18. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  19. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/30 22:21:04
  20. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/1 4:32:01
  21. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/4 2:59:34
  22. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  23. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  24. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/2 9:07:46
  25. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57