Linux异常(中断)处理体系结构

2023-11-05

前言:可以调到总结处先看明白这篇文章要说明的内容,再回到开头看。

1. 异常

异常,就是可以打断CPU正常运行流程的一些事情,比如:外部中断、未定义的指令、企图修改只读的数据、执行SWI指令(Software Interrupt Instruction,软件中断指令)等。

当这些事情发生时,CPU暂停当前的程序,先处理异常事件,然后再继续执行被中断的程序。操作系统中经常通过异常来完成一些特定的功能。

例如:

  • 当CPU执行未定义的机器指令时将触发“未定义指令异常”,操作系统可以利用这个特点使用一些自定义的机器指令,它们在异常处理函数中实现。

  • 可以将一块数据设为只读的,然后提供给多个进程共用,这样可以节省内存。当某个进程试图修改其中的数据时,将触发“数据访问中止异常”,在异常处理函数中将这块数据复制出来一份可写的副本,提供给这个进程使用。

  • 当用户程序试图读写的数据或执行的指令不在内存时,也会触发一个“数据访问中止异常”或“指令预取中止异常”。在异常处理函数中将这些数据或指令读入内存(内存不足时可以将不使用的数据、指令换出内存),然后重新执行被中断的程序。这样可以节省内存,还可以使得操作系统可以运行这类程序:它们使用的内存远大于实际的物理内存。

  • 当程序使用不对齐的地址访问内存时,也会触发“数据访问中止异常”,在异常处理程序中先使用多个对齐的地址读出数据;

    对于读操作,从中选取数据组合好后返回给被中断的程序;

    对于写操作,修改其中的部分数据后再写入内存。

    这使得程序不用考虑地址对齐的问题。

  • 用户程序可以通过“SWI”指令触发“SWI异常”,操作系统在swi异常处理函数中实现各种系统调用。

2. Linux内核对异常的初始化

内核在start_kernel函数(init/main.c中)调用trap_initinit_IRQ这两个函数来设置异常的处理函数。

2.1 trap_init 函数分析

trap_init 函数(代码在arch/arm/kernel/traps.c中)被用来设置各种异常的处理向量,包括中断向量。

所谓“向量”,就是一些被安放在固定位置的代码,当发送异常时,CPU会自动执行这些固定位置上的指令。

ARM架构CPU异常向量基址可以是0x00000000,也可以是0xffff0000,Linux内核使用后者。

trap_init 函数将异常向量复制到0xffff0000处,部分代码如下:

void __init trap_init(void)
{
    // 省略
	memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
	memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
	memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
	// 省略
}

vectors 等于0xffff0000。地址 __vectors_start ~ __vectors_ends 之间的代码就是异常向量,在 arch/arm/kernel/entry-armv.S 中定义,它们被复制到地址0xffff0000处。

异常向量的代码很简单,它们只是一些跳转指令。发生异常时,CPU自动执行这些指令,跳转去执行更复杂的代码,比如保存被中断程序的执行环境,调用异常处理函数,恢复被中断程序的执行环境并重新运行。这些“更复杂的代码”在地址 __stubs_start ~ __stubs_end 之间,它们定义在 arch/arm/kernel/entry-armv.S 。

memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start); 将它们复制到地址0xffff0000+0x200处。

异常向量、异常向量跳去执行的代码都是使用汇编写的:

	.globl	__vectors_start
__vectors_start:
	swi	SYS_ERROR0							/* 复位时,CPU将执行这条指令 */
	b	vector_und + stubs_offset			/* 未定义异常时,CPU将执行这条指令 */
	ldr	pc, .LCvswi + stubs_offset			/* SWI异常 */
	b	vector_pabt + stubs_offset			/* 指令预取中止 */
	b	vector_dabt + stubs_offset			/* 数据访问中止 */
	b	vector_addrexcptn + stubs_offset	/* 没有用到 */
	b	vector_irq + stubs_offset			/* irq异常 */
	b	vector_fiq + stubs_offset			/* fiq异常 */

	.globl	__vectors_end
__vectors_end:

其中 vector_undvector_pabt 表示要跳转去执行的代码。以 vector_und 为例,它仍然在 arch/arm/kernel/entry-armv.S 中,通过 vector_stub 宏定义,代码如下:

/*
 * Undef instr entry dispatcher
 * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
 */
	vector_stub	und, UND_MODE

	.long	__und_usr				@  0 (USR_26 / USR_32)	用户模式执行了未定义的指令
	.long	__und_invalid			@  1 (FIQ_26 / FIQ_32)	在FIQ模式执行了未定义的指令
	.long	__und_invalid			@  2 (IRQ_26 / IRQ_32)	在IRQ模式执行了未定义的指令
	.long	__und_svc				@  3 (SVC_26 / SVC_32)	在管理模式执行力未定义的指令
	.long	__und_invalid			@  4
	.long	__und_invalid			@  5
	.long	__und_invalid			@  6
	.long	__und_invalid			@  7
	.long	__und_invalid			@  8
	.long	__und_invalid			@  9
	.long	__und_invalid			@  a
	.long	__und_invalid			@  b
	.long	__und_invalid			@  c
	.long	__und_invalid			@  d
	.long	__und_invalid			@  e
	.long	__und_invalid			@  f

	.align	5

第5行的 vector_stub 是一个宏,它根据后面的参数 “und, UND_MODE” 定义了以 vector_und 为标号的一段代码。

vector_stub的定义如下:

/*
 * Vector stubs.
 *
 * This code is copied to 0xffff0200 so we can use branches in the
 * vectors, rather than ldr's.  Note that this code must not
 * exceed 0x300 bytes.
 *
 * Common stub entry macro:
 *   Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
 *
 * SP points to a minimal amount of processor-private memory, the address
 * of which is copied into r0 for the mode specific abort handler.
 */
	.macro	vector_stub, name, mode, correction=0
	.align	5

vector_\name:
	.if \correction
	sub	lr, lr, #\correction
	.endif

	@
	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
	@ (parent CPSR)
	@
	stmia	sp, {r0, lr}		@ save r0, lr
	mrs	lr, spsr
	str	lr, [sp, #8]			@ save spsr

	@
	@ Prepare for SVC32 mode.  IRQs remain disabled.
	@
	mrs	r0, cpsr
	eor	r0, r0, #(\mode ^ SVC_MODE)
	msr	spsr_cxsf, r0

	@
	@ the branch table must immediately follow this code
	@
	and	lr, lr, #0x0f
	mov	r0, sp
	ldr	lr, [pc, lr, lsl #2]
	movs	pc, lr			@ branch to handler in SVC mode
	.endm

vector_stub 宏的功能:计算处理完异常后的返回地址、保存一些寄存器(r0、lr、spsr),然后进入管理模式,最后根据被中断的工作模式跳转到某个分支。

当发生异常时,CPU 会根据异常的类型进入某个工作模式,但是很快 vector_\name 宏又会限制 CPU 进入管理模式,在管理模式下进行后续的处理,这种方式简化了程序设计,使得异常发生前的工作模式要么是用户模式,要么是管理模式。

因此,完整的 vector_und 代码如下:

vector_und:
	@
	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
	@ (parent CPSR)
	@
	stmia	sp, {r0, lr}		@ save r0, lr
	mrs	lr, spsr
	str	lr, [sp, #8]			@ save spsr

	@
	@ Prepare for SVC32 mode.  IRQs remain disabled.
	@
	mrs	r0, cpsr
	eor	r0, r0, #(\mode ^ SVC_MODE)
	msr	spsr_cxsf, r0

	@
	@ the branch table must immediately follow this code
	@
	and	lr, lr, #0x0f
	mov	r0, sp
	ldr	lr, [pc, lr, lsl #2]
	movs	pc, lr			@ branch to handler in SVC mode
	
    .long	__und_usr				@  0 (USR_26 / USR_32)	用户模式执行了未定义的指令
	.long	__und_invalid			@  1 (FIQ_26 / FIQ_32)	在FIQ模式执行了未定义的指令
	.long	__und_invalid			@  2 (IRQ_26 / IRQ_32)	在IRQ模式执行了未定义的指令
	.long	__und_svc				@  3 (SVC_26 / SVC_32)	在管理模式执行力未定义的指令
	.long	__und_invalid			@  4
	.long	__und_invalid			@  5
	.long	__und_invalid			@  6
	.long	__und_invalid			@  7
	.long	__und_invalid			@  8
	.long	__und_invalid			@  9
	.long	__und_invalid			@  a
	.long	__und_invalid			@  b
	.long	__und_invalid			@  c
	.long	__und_invalid			@  d
	.long	__und_invalid			@  e
	.long	__und_invalid			@  f

vector_und 会跳转到__und_usr__und_svc__und_invalid等16个不同的分支。

  • __und_usr:表示在用户模式下执行未定义指令时,所发送的未定义异常将由它来处理;
  • __und_svc:表示在管理模式下执行未定义指令时,所发送的未定义异常将由它来处理;
  • __und_invalid:其它工作模式下不可能发送未定义指令异常,否则使用该分支。

不同的跳转分支只是在它们的入口处,保存被中断程序寄存器稍微有差别,后续的处理大体相同,都是调用C函数。比如未定义指令异常发生时,最终会调用C函数 do_undefinstr 来进行处理。各种异常的C处理函数可以分为5类,它们分布在不同的文件中:

  1. arch/arm/kernel/traps.c:未定义指令异常的C处理函数在这个文件中定义,总入口函数为 do_undefinstr.
  2. arch/arm/mm/fault.c:与内存访问相关的异常的C处理函数在这个文件中定义,比如数据访问中止异常、指令预取中止异常。总入口函数为 do_DataAbort、do_PrefetchAbort。
  3. arch/arm/mm/irq.c:中断处理函数的在这个文件中定义,总入口函数为 asm_do_IRQ,它调用其他文件注册的中断处理函数。
  4. arch/arm/kernel/calls.S:在这个文件中,SWI 异常的处理函数指针被组织成一个表格。SWI 指令机器码的位[23:0]被用来作为索引。这样,通过不同的“swi index”指令就可以调用不同的 SWI 异常处理函数,它们被称为系统调用,比如:sys_open、sys_read、sys_write 等。 ARM 软中断指令_SWI指令

在 Linux 2.6.22.6 中没有使用 FIQ 异常。

通过对不同异常向量的分析,我们最终可以得到如下面的 ARM 架构下的 Linux 异常处理体系结构图:
在这里插入图片描述

3. Linux中断处理体系结构

中断也是一种异常,中断的处理与具体的开发板密切相关,除了一些必须、共用的中断(比如:系统时钟中断、片内外设UART中断)外,必须由驱动开发者提供处理函数。

内核提炼出了中断处理的共性,搭建了一个非常容易扩充的中断处理体系。

3.1 init_IRQ 函数分析

init_IRQ 函数(代码在arch/arm/kernel/irq.c中)被用来初始化中断的处理框架,设置各种中断默认处理函数。

当发生中断时,中断入口函数 asm_do_IRQ 就可以调用 init_IRQ 初始化好了的函数作进一步处理。

Linux 内核对所有的中断统一编号,使用一个 irq_desc 结构数组来描述这些中断:每个数组项对应一个中断。(也有可能是一组中断,它们共用相同的中断号)结构体里面记录了中断的名称、中断状态(比如中断类型、是否共享中断等),并提供了中断的底层硬件访问函数(清除、屏蔽、使能中断),提供了这个中断的处理函数入口,通过它可以调用用户注册的中断处理函数。

3.2 中断数据结构

irq_desc 结构体:

struct irq_desc {
	irq_flow_handler_t	handle_irq;	/* 当前中断的处理函数函数入口 */
	struct irq_chip		*chip;		/* 低层的硬件访问 */
	/* ...省略... */
	struct irqaction	*action;	/* 用户提供的中断处理函数链表 */
	unsigned int		status;		/* IRQ 状态 */
	/* ...省略... */
	const char		*name;			/* 中断的名字 */
};

handle_irq:是这个或这组中断的处理函数入口。发送中断时,总入口函数 asm_do_IRQ 将根据中断号调用相应 irq_desc 数组项中的 handle_irq。

handle_irq 使用 chip 结构中的函数来清除、屏蔽或者重新使能中断,还一一调用用户在 action 链表中注册的中断处理函数。

irq_chip 结构:

struct irq_chip {
	const char	*name;
	unsigned int	(*startup)(unsigned int irq);	/* 启动中断,如果不设置,缺省为enable */
	void		(*shutdown)(unsigned int irq);		/* 关闭中断,如果不设置,缺省为disable */
	void		(*enable)(unsigned int irq);		/* 使能中断,如果不设置,缺省为unmask */
	void		(*disable)(unsigned int irq);		/* 禁止中断,如果不设置,缺省为mask */
	void		(*ack)(unsigned int irq);			/* 响应中断,通常是清除当前中断使得可以接收下一个中断 */
	void		(*mask)(unsigned int irq);			/* 屏蔽中断源 */
	void		(*mask_ack)(unsigned int irq);		/* 屏蔽和响应中断 */
	void		(*unmask)(unsigned int irq);		/* 开启中断源 */
	/* ...省略... */
};

该结构体中的成果大多用于操作底层硬件,比如设置寄存器以屏蔽中断、使能中断、清除中断等。

irqaction 结构:

struct irqaction {
	irq_handler_t handler;	/* 用户注册的中断处理函数 */
	unsigned long flags;	/* 中断标志,比如:是否共享中断、电平触发还是边沿触发等 */
	cpumask_t mask;			/* 用于SMP(对称多处理器系统) */
	const char *name;		/* 用户注册的中断名字,"cat/proc/interrupts"时可以看到 */
	void *dev_id;			/* 用户传给上面的handler参数,还可以用来区分共享中断 */
	struct irqaction *next;
	int irq;				/* 中断号 */
	struct proc_dir_entry *dir;
};

irq_desc 结构数组和它的成员 struct irq_chip *chip、struct irqaction *action 构成了中断处理体系的构架。
在这里插入图片描述

3.3 中断处理流程

  1. 发生中断时,CPU执行异常向量 vector_irq 的代码;
  2. 在 vector_irq 里面,最终会调用中断处理的总入口函数 asm_do_IRQ;
  3. asm_do_IRQ 根据中断号调用 irq_desc 数组项中的 handle_irq;
  4. handle_irq 会使用 chip 成员中的函数来设置硬件,比如清除中断、禁止中断、重新使能中断等;
  5. handle_irq 逐个调用用户在 action 链表中注册的处理函数;

可见,中断体系结构的初始化就是构造这些数据结构,比如 irq_desc 数组中的 handle_irq、chip 等这些数据结构。用户注册中断时就是构造 action 链表;用户卸载中断时就是从 action 链表中去除不需要的项。

其大致的流程如下:首先外设产生异常(也叫中断),经过一些列处理后,中断返回,回到被中断程序继续执行。
在这里插入图片描述

3.4 asm_do_IRQ 函数

vector_irq 在 arch/arm/kernel/entry-armv.S 中定义:(对 vector_\name 进行了展开)

vector_irq:
	sub	lr, lr, 4
	
	@
	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
	@ (parent CPSR)
	@
	stmia	sp, {r0, lr}		@ save r0, lr
	mrs	lr, spsr
	str	lr, [sp, #8]		@ save spsr

	@
	@ Prepare for SVC32 mode.  IRQs remain disabled.
	@
	mrs	r0, cpsr
	eor	r0, r0, #(\mode ^ SVC_MODE)
	msr	spsr_cxsf, r0

	@
	@ the branch table must immediately follow this code
	@
	and	lr, lr, #0x0f
	mov	r0, sp
	ldr	lr, [pc, lr, lsl #2]
	movs	pc, lr			@ branch to handler in SVC mode

	.long	__irq_usr				@  0  (USR_26 / USR_32)
	.long	__irq_invalid			@  1  (FIQ_26 / FIQ_32)
	.long	__irq_invalid			@  2  (IRQ_26 / IRQ_32)
	.long	__irq_svc				@  3  (SVC_26 / SVC_32)
	.long	__irq_invalid			@  4
	.long	__irq_invalid			@  5
	.long	__irq_invalid			@  6
	.long	__irq_invalid			@  7
	.long	__irq_invalid			@  8
	.long	__irq_invalid			@  9
	.long	__irq_invalid			@  a
	.long	__irq_invalid			@  b
	.long	__irq_invalid			@  c
	.long	__irq_invalid			@  d
	.long	__irq_invalid			@  e
	.long	__irq_invalid			@  f

用户模式的中断指令 __irq_usr的定义如下:

__irq_usr:
	usr_entry
	/* ...省略... */
	irq_handler
	/* ...省略... */
	b	ret_to_user

其中 irq_handler 的定义如下:

	.macro	irq_handler
	get_irqnr_preamble r5, lr
1:	get_irqnr_and_base r0, r6, r5, lr
	movne	r1, sp
	@
	@ routine called with r0 = irq number, r1 = struct pt_regs *
	@
	adrne	lr, 1b
	bne	asm_do_IRQ

最终会调用 asm_do_IRQ 函数进行中断的处理操作。在此之前看一下 get_irqnr_and_base r0, r6, r5, lr 这条指令,get_irqnr_and_base 也是一个宏定义,其源码如下:

	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp

		mov	\base, #S3C24XX_VA_IRQ

		@@ try the interrupt offset register, since it is there

		ldr	\irqstat, [ \base, #INTPND ]
		teq	\irqstat, #0
		beq	1002f
		ldr	\irqnr, [ \base, #INTOFFSET ]
		mov	\tmp, #1
		tst	\irqstat, \tmp, lsl \irqnr
		bne	1001f

		@@ the number specified is not a valid irq, so try
		@@ and work it out for ourselves

		mov	\irqnr, #0		@@ start here

		@@ work out which irq (if any) we got

		movs	\tmp, \irqstat, lsl#16
		addeq	\irqnr, \irqnr, #16
		moveq	\irqstat, \irqstat, lsr#16
		tst	\irqstat, #0xff
		addeq	\irqnr, \irqnr, #8
		moveq	\irqstat, \irqstat, lsr#8
		tst	\irqstat, #0xf
		addeq	\irqnr, \irqnr, #4
		moveq	\irqstat, \irqstat, lsr#4
		tst	\irqstat, #0x3
		addeq	\irqnr, \irqnr, #2
		moveq	\irqstat, \irqstat, lsr#2
		tst	\irqstat, #0x1
		addeq	\irqnr, \irqnr, #1

		@@ we have the value
1001:
		adds	\irqnr, \irqnr, #IRQ_EINT0
1002:
		@@ exit here, Z flag unset if IRQ

	.endm

大致可以看得出,该宏读取了 INTPND、INTOFFSET 等寄存器,也就获取了中断的中断号。将中断号放在 r0 寄存器里,在后面传给 asm_do_IRQ 函数。

asm_do_IRQ 的定义如下:

asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
	struct pt_regs *old_regs = set_irq_regs(regs);
	struct irq_desc *desc = irq_desc + irq;

	/*
	 * Some hardware gives randomly wrong interrupts.  Rather
	 * than crashing, do something sensible.
	 */
	if (irq >= NR_IRQS)
		desc = &bad_irq_desc;

	irq_enter();

	desc_handle_irq(irq, desc);

	/* AT91 specific workaround */
	irq_finish(irq);

	irq_exit();
	set_irq_regs(old_regs);
}

struct irq_desc *desc = irq_desc + irq;:获取 irq 对应的 irq_desc 数据结构;

desc_handle_irq(irq, desc);:根据 desc 中记录的操作函数,对 irq 进行处理;

而对于 __irq_svc 类型的异常处理与 __irq_usr 的非常相似,不做累述。

4. 总结

通过上面的分析我们大致弄明白了 ARM 架构下 Linux 整个的异常处理流程。

Linux 系统启动时,会在 start_kernel 函数中调用一些列初始化函数:

  1. 包括 trap_init 函数。

    trap_init 函数完成的工作:将中断向量表拷贝到 0xffff0000 处,这个地址是我们在编译内核时指定的。

    也不一定是0xffff0000,根据不同的芯片可能会选择中断向量表的存放地址。例如:s3c2440芯片就规则了中断向量表存放的地址为 0x00000000 或 0xffff0000 两个地址,通过配置寄存器来选择不同的地址。

  2. 接着内核会调用 init_IRQ 函数,完成中断数据结构 irq_desc 的初始化工作。

    包括设置全局的 irq_desc 数组,根据 NR_IRQS 这个宏定义,设置一个大小为 NR_IRQS 的中断数组。NR_IRQS 指定了内核支持的中断种类的个数。

    同时填充每一个 irq_desc 结构体的 irq_chip 和 handle_irq 结构。前者包含了硬件相关的操作,包括使芯片使能中断,清除中断等硬件相关的操作;后者指定了发送中断时要掉调用的中断请求的处理函数。

    并且对每一个 irq_desc 设置默认的操作函数,如果应用程序没有指定特定的操纵函数,后续触发中断时都会调用默认的操作函数。

完成上面的工作后,中断的初始化就完成了。

当有中断被触发时,通过中断向量表,最终会进入 asm_do_IRQ 函数。该函数会根据中断号,从全局的 irq_desc 数组中获取到中断号对应的 irq_desc,再根据其内部设置的 irq_chip 和 handle_irq 完成对中断请求的响应。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux异常(中断)处理体系结构 的相关文章

  • Linux:通过网络进行屏幕桌面视频捕获和 VNC 帧速率

    抱歉 文字墙很长 TL DR VNC 连接的帧速率是多少 以帧 秒为单位 或者更确切地说 由谁决定 客户端还是服务器 对于桌面屏幕捕获的任何其他建议 但 正确的时间编码 具有不抖动的帧速率 具有稳定的周期 并有可能将其作为未压缩 或无损 图
  • 如何真正释放 Linux 中的大页面以供新进程使用?

    真的找不到太多关于此的信息 希望有人可以提供帮助 我正在假脱机使用 100GB java 堆作为大数据缓存 为了避免与文件系统缓存等内容发生冲突 并且因为它通常性能更好 我将其分配在大页面中 我保留了 51 200 x 2MB 大页面 一切
  • Nasm 打印到下一行

    我用 nasm Assembly 编写了以下程序 section text global start start Input variables mov edx inLen mov ecx inMsg mov ebx 1 mov eax 4
  • 在键盘热插拔上加载模块

    我正在尝试学习如何为 Linux 系统编写模块和驱动程序 类似于this https unix stackexchange com questions 120839 usb kernel module does not load on de
  • 是否可以找到哪个用户位于 localhost TCP 连接的另一端?

    这是一个编程问题 但它是 Linux Unix 特定的 如果我从本地主机获得 TCP 连接 是否有一种简单的方法可以告诉哪个用户在 C 程序内建立了连接而无需 shell 我知道这对于 Unix 域套接字来说并不太难 我已经知道远程 IP
  • 使用 C++ 输出字符串覆盖 Linux 终端上的最后一个字符串

    假设我有一个命令行程序 有没有办法让我说的时候 std cout lt lt stuff 如果我不做std cout lt lt n 在另一个之间std cout lt lt stuff 东西的另一个输出将覆盖同一行上的最后一个东西 清理行
  • Linux TCP服务器:在接受连接之前读取客户端的IP地址

    Related C Winsock API如何在接受连接之前获取连接客户端IP https stackoverflow com questions 716209 c winsock api how to get connecting cli
  • Docker DNS 设置

    我尝试使用自定义网络和 dos 设置创建 docker 容器 docker网络创建 driver bridge opt com docker network bridge enable ip masquerade true opt com
  • 如何在 Linux 中使用单行命令获取 Java 版本

    我想通过单个命令获取 Linux 中的 Java 版本 我是 awk 的新手 所以我正在尝试类似的事情 java version awk print 3 但这不会返回版本 我将如何获取1 6 0 21从下面的Java版本输出 java ve
  • UDP 广播发送失败:在 Linux 2.6.30 上“网络无法访问”

    我用udp广播写了一个程序 代码段如下 struct sockaddr in broadcast addr socklen t sock len sizeof broadcast addr bzero broadcast addr sock
  • 如何在两个不同帐户之间设置无密码身份验证

    我们可以在两台机器的两种不同用途之间设置无密码身份验证吗 例如 计算机A有用户A 计算机B有用户B 我们可以设置密码 ssh 以便计算机 A 上的用户 A 使用其用户帐户 A 登录计算机 B 谢谢你 如果我理解你的问题 你能设置一下吗ssh
  • 编写多个mysql脚本

    是否可以在复合脚本中包含其他 mysql 脚本 理想情况下 我不想为包含的脚本创建存储过程 对于较大的项目 我想分层维护几个较小的脚本 然后根据需要组合它们 但现在 我很乐意学习如何包含其他脚本 source是一个内置命令 您可以在 MyS
  • Linux 文本文件操作

    我有一个格式的文件 a href a href a href a href 我需要选择 之后但 之前的文本 并将其打印在行尾 添加后 例如 a href http www wowhead com search Su a a a a a
  • 使用脚本自动输入 SSH 密码

    我需要创建一个自动向 OpenSSH 输入密码的脚本ssh client 假设我需要通过 SSH 进入myname somehost用密码a1234b 我已经尝试过 bin myssh sh ssh myname somehost a123
  • Windows 与 Linux 文本文件读取

    问题是 我最近从 Windows 切换到 Ubuntu 我的一些用于分析数据文件的 python 脚本给了我错误 我不确定如何正确解决 我当前仪器的数据文件输出如下 Header 有关仪器等的各种信息 Data 状态 代码 温度 字段等 0
  • linux下如何获取昨天和前天?

    我想在变量中获取 sysdate 1 和 sysdate 2 并回显它 我正在使用下面的查询 它将今天的日期作为输出 bin bash tm date Y d m echo tm 如何获取昨天和前天的日期 这是另一种方法 对于昨天来说 da
  • Gradle 1.3:build.gradle 不构建类

    这里有一个新问题 我有一个 build gradle 文件apply plugin java在其中 并与 java 项目 包关联 当我跑步时gradle build从命令行我得到 compileJava UP TO DATE process
  • 为什么 ld 无法从 /etc/ld.so.conf 中的路径找到库?

    我想添加 opt vertica lib64进入系统库路径 所以我执行以下步骤 1 添加 opt vertica lib64 into etc ld so conf 然后运行ldconfig 2 检查 bash ldconfig p gre
  • Bash 脚本 - 迭代 find 的输出

    我有一个 bash 脚本 其中需要迭代 find 命令输出的每一行 但似乎我正在迭代 find 命令中的每个单词 以空格分隔 到目前为止我的脚本看起来像这样 folders find maxdepth 1 type d for i in f
  • 我应该使用哪个 Linux 发行版作为 Xen 主机? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我为家庭办公室订购了一台服务器 我想用 Xen 对其进行分区 我认为这将使事情保持干净并且更容易维护 我将运行 MySQL PostgreSQL

随机推荐

  • 创米云入驻集简云平台,实现无代码集成数百款应用

    PART 1 创米云介绍 创米云科技 是一家专注于小程序开发 同时也是 微信 阿里本地生活客如云 支付宝 的优质IT技术服务商 国内领先自主研发的小程序开发工具 制作过程无需代码 拖拽可视化组件即可完成 拥有海量小程序行业模板 帮助千万商户
  • python 饼图、直方图、散点图和盒图基本绘制

    文章目录 python 饼图 直方图 散点图和盒图基本绘制 饼图 直方图 使用pygal 使用pyplot 散点图 例1 例2 例3 盒图 python 饼图 直方图 散点图和盒图基本绘制 饼图 import matplotlib pypl
  • 将STM32工程下载到GD32中

    在已经写好stm32f103工程的情况下 将stm的工程直接下载到GD32的开发板中 1 导入GD32的pack包 选择使用的芯片型号 并将flash download换为GD32的 2 修改工程参考 STM32移植到GD32 3 如果代码
  • JAVA static修饰符

    static修饰的属于类本身 没有static修饰的属于实例 创建类时 static修饰的成员存放在堆内存中的permanent代 permanent代存放类的信息 如类中的static的成员 class a static int n 4
  • JDBC连接数据库工具类

    最近有人问加哥怎么连接数据库 和数据库建立连接 下面给大家分享一下JDBC连接数据库的模版方法 加哥是以mysql为例 若是其他数据库替换层其他的即可 步骤 1 引入数据库架包 2 加载驱动 3 创建连接 4 进行相应数据库操作 5 关闭数
  • fastreport在delphi中的使用

    文章目录 前言 一 发布后的设计 二 小计 三 分组 1 分组时 MasterData选择保持一致性 2 分组设置 四 页码 五 透视表 前言 记录fastreport在delphi中的使用方法 一 发布后的设计 程序发布后 需要在客户那边
  • 链表的定义和基本操作

    文章目录 单链表 定义 插入操作 删除操作 查找操作 单链表的建立 双链表 初始化 插入 删除 遍历 循环链表 初始化 单链表 定义 要表示一个单链表时 只需要声明一个头指针L 指向单链表的第一个节点 LNode L 或者 LinkList
  • C++基础——this指针

    目录 一 this指针 1 this指针定义 2 this指针的特性 3 this指针存在的位置 一 this指针 例 class Date public void Print int year int month int day cout
  • WDK李宏毅学习笔记重点知识复习总结

    李宏毅学习笔记复习总结 文章目录 李宏毅学习笔记复习总结 1 Regression 回归 和 Classification 分类 1 1 是什么 1 2 怎么做 2 Deep Learning 2 1 是什么 2 2 怎么做 3 CNN 卷
  • 什么是dns流量?如何监控dns流量

    DNS是重要的基础设施 用于域名服务 在负载均衡 移动IP等方面也有着重要的应用 DNS流量激增对互联网的正常运作的影响 并提出了恶意DNS流量攻击 蜂窝效应概念 什么是DNS流量 监控它的方法有哪些 一起来看看吧 什么是DNS流量 dns
  • 基于互联网的信号传输系统

    参加完电子设计竞赛不知不觉快过去两个月了 今天小刚写一下当时我们这道题的方案 本系统基于互联网的信号传输系统采用STM32F407ZGT6和FPGA Cyclone IV作为主控芯片 对信号进行采样和处理 系统由幅度测量电路 频率测量电路
  • Flask框架之视图高级技巧

    文章目录 4 1 app route与app url rule简介 4 1 1 app route的使用 4 1 2 add url rule的使用 4 2 Flask类视图 4 2 1 标准类视图 4 2 2 基于方法的类视图 4 3 F
  • win10c语言文件不运行,教你解决win10系统无法打开EXE文件的问题

    win10电脑上的程序一般都是exe格式的 鼠标双击一下即可运行 最近 有Win10系统的用户抱怨说竟然打不开Exe的文件 双击好多次了 甚至关机重启还是一样打不开Exe的文件 真是让人感到疑惑 其实 遇到此故障问题不必慌张 大家可以尝试按
  • 拜耳再投4亿元提升在华处方药产能;阿斯利康进博会公布新冠疫苗最新进展

    进博会看点 拜耳围绕 共享健康 消除饥饿 的全新企业愿景 携一系列亮点展品和精彩活动亮相进博会 进博会上 拜耳与北京经济技术开发区签署合作意向书 拜耳今年在公共卫生防疫专区设置独立的展台 并呈现覆盖预防 诊断 缓解及治疗于一体的医疗解决方案
  • vue3+ts 使用qrcode(解决了找不到qrcode类型声明文件问题)

    1 安装 全局安装 npm install g qrcode 安装类型声明 npm i save dev types qrcode 2 在所需处引用 import QRcode from qrcode 3 配合canvas 生成二维码
  • datax 数据写入oracle报错缺失表达式_实战再次升级:流批一体处理百亿级别数据...

    需求背景 该篇内容基于之前写过的一篇 lt gt 上一篇文章其实主要重点是结合logstash的实际应用 近期业务方提出了新的需求 增加了些业务逻辑 同时数据量也成倍增加 要求每日产出指标结果 这里再回顾下上篇的数据情况和技术方案同时对比下
  • word 文档标题样式相同、行距效果不同的解决办法

    先看下图示例 两个标题均采用了标题1的样式 段前 段后0 5行 单倍行距 但展现出的效果有很大差异 修改办法 将鼠标放置在需要修改的标题页 菜单栏点击 布局 gt 点击 页面设置 右下角扩展按钮 gt 点击 文档网络 调整成和第二章一样的行
  • ruoyi 修改主题颜色

    ruoyi 修改主题颜色 找到样式文件 src main resources static css skins css 1 修改顶部右侧导航栏背景颜色 skin yellow navbar background color 4EA3E4 2
  • 通用语言大模型都是人、机、环境系统智能

    通用语言大模型可以被看作是人 机 环境系统智能发展的早期阶段之一 这些模型使用深度学习和自然语言处理等技术 通过对大量数据的学习和训练 能够生成具有语义理解和生成能力的文本回答 在这个系统中 人类作为用户与AI模型进行交互 提供问题或指令
  • Linux异常(中断)处理体系结构

    前言 可以调到总结处先看明白这篇文章要说明的内容 再回到开头看 1 异常 异常 就是可以打断CPU正常运行流程的一些事情 比如 外部中断 未定义的指令 企图修改只读的数据 执行SWI指令 Software Interrupt Instruc