目录

1.概述

2.高级SIMD和浮点寄存器介绍

2.NEON指令

2.1 VLDR

2.2 VLDM

2.3 VSTR

2.4 VSTM

3.ARM架构程序调用寄存器使用规则

3.1.ARM寄存器使用规则

3.2.NEON寄存器使用规则

3.优化代码

3.1.memcpy_libc

3.2.memcpy_1

3.3.memcpy_32

3.4.memcpy_64

3.5.memcpy_gen

3.7.memcpy_neon_128

3.速度测试

3.1.对齐拷贝测试(单位:MiB/s)

3.2.非对齐拷贝测试(单位:MiB/s)

4.影响拷贝速度的因素

5.结论


1.概述

内存非cache区域拷贝速度很慢,严重影响了系统性能,因此采用多种方法进行优化,主要有对齐拷贝、批量拷贝、减少循环次数、NEON拷贝方法。

2.高级SIMD和浮点寄存器介绍

2.NEON指令

2.1 VLDR

VLDR指令可从内存中将数据加载到扩展寄存器中。

VLDR{<c>}{<q>}{.64} <Dd>, [<Rn> {, #+/-<imm>}]   Encoding T1/A1, immediate form
VLDR{<c>}{<q>}{.64} <Dd>, <label>                Encoding T1/A1, normal literal form
VLDR{<c>}{<q>}{.64} <Dd>, [PC, #+/-<imm>]        Encoding T1/A1, alternative literal form
VLDR{<c>}{<q>}{.32} <Sd>, [<Rn> {, #+/-<imm>}]   Encoding T2/A2, immediate form
VLDR{<c>}{<q>}{.32} <Sd>, <label>                Encoding T2/A2, normal literal form
VLDR{<c>}{<q>}{.32} <Sd>, [PC, #+/-<imm>]        Encoding T2/A2, alternative literal form

<c>,<q>:是一个可选的条件代码。
.32,.64:是一个可选的数据大小说明符。如果是单精度VFP寄存器,则必须为32;否则必须为64。
Dd:双字(64位)加载的目标寄存器。对于NEON指令,它必须为D寄存器。对于VFP指令,它可以为D或S寄存器。
Sd:单字(32位)加载的目标寄存器。对于NEON指令,它必须为D寄存器。对于VFP指令,它可以为D或S寄存器。
Rn:存放要传送的基址的ARM寄存器,SP可使用。
+/-:偏移量相对于基地址的运算方式,+表示基地址和偏移量相加,-表示基地址和偏移量相减,+可以省略,#0和#-0生成不同的指令。
imm:是一个可选的数值表达式。在汇编时,该表达式的值必须为一个数字常数。 该值必须是4的倍数,并在0 - 1020的范围内。该值与基址相加得到用于传送的地址。
label:要加载数据项的标签。编译器自动计算指令的Align(PC, 4)值到此标签的偏移量。允许的值是4的倍数,在-1020到1020的范围内。

2.2 VLDM

VLDM指令可以将连续内存地址中的数据加载到扩展寄存器中。

VLDM{<mode>}{<c>}{<q>}{.<size>} <Rn>{!}, <list>

<mode>:IA Increment After,连续地址的起始地址在Rn寄存器中,先加载数据,然后Rn寄存器中的地址在增大,这是缺省的方式,DB Decrement Before,连续地址的起始地址在Rn寄存器中,Rn寄存器中的地址先减小,再加载数据
<c>,<q>:是一个可选的条件代码。
<size>:是一个可选的数据大小说明符。取32或64,和<list>中寄存器的位宽一致。
Rn:存放要传送的基址的ARM寄存器,由ARM指令设置,SP可使用。
!:表示Rn寄存器中的内容变化时要将变化的值写入Rn寄存器中。
<list>:加载的扩展寄存器列表。至少包含一个寄存器,如果包含了64位寄存器,最多不超过16个寄存器。

2.3 VSTR

VSTR指令将扩展寄存器中的数据保存到内存中。

VSTR{<c>}{<q>}{.64} <Dd>, [<Rn>{, #+/-<imm>}] Encoding T1/A1
VSTR{<c>}{<q>}{.32} <Sd>, [<Rn>{, #+/-<imm>}] Encoding T2/A2

<c>,<q>:是一个可选的条件代码。
.32,.64:是一个可选的数据大小说明符。如果是单精度VFP寄存器,则必须为32;否则必须为64。
Dd:双字(64位)加载的目标寄存器。对于NEON指令,它必须为D寄存器。对于VFP指令,它可以为D或S寄存器。
Sd:但字(32位)加载的目标寄存器。对于NEON指令,它必须为D寄存器。对于VFP指令,它可以为D或S寄存器。
Rn:存放要传送的基址的ARM寄存器,SP可使用。
+/-:偏移量相对于基地址的运算方式,+表示基地址和偏移量相加,-表示基地址和偏移量相减,+可以省略,#0和#-0生成不同的指令。
imm:是一个可选的数值表达式。在汇编时,该表达式的值必须为一个数字常数。 该值必须是4的倍数,并在0 - 1020的范围内。该值与基址相加得到用于传送的地址。

2.4 VSTM

VSTM指令可将扩展寄存器列表中的数据保存到连续的内存中。

<mode>:IA Increment After,连续地址的起始地址在Rn寄存器中,先保存数据,然后Rn寄存器中的地址在增大,这是缺省的方式,DB Decrement Before,连续地址的起始地址在Rn寄存器中,Rn寄存器中的地址先减小,再保存数据
<c>,<q>:是一个可选的条件代码。
<size>:是一个可选的数据大小说明符。取32或64,和<list>中寄存器的位宽一致。
Rn:存放要传送的基址的ARM寄存器,由ARM指令设置,SP可使用。
!:表示Rn寄存器中的内容变化时要将变化的值写入Rn寄存器中。
<list>:保存的扩展寄存器列表。至少包含一个寄存器,如果包含了64位寄存器,最多不超过16个寄存器。

3.ARM架构程序调用寄存器使用规则

3.1.ARM寄存器使用规则

(1)子程序间通过寄存器R0-R3传递参数,被调用的子程序在返回前无须恢复寄存器R0-R3的内容,参数多余4个时,使用栈传递,参数入栈的顺序与参数顺序相反。
(2)在子程序中,使用寄存器R4-R11保存局部变量,如果子程序中使用了R4-R11的寄存器,则必须在使用之前保存这些寄存器,子程序返回之前恢复这些寄存器,在子程序中没有使用这些寄存器,则无须保存。
(3)寄存器R12用作子程序间的scratch寄存器,记作IP,在子程序间的链接代码段中常有这种规则。
(4)寄存器R13用作数据栈指针,记作SP。在子程序中,寄存器R13不能用作其它用途。
(5)寄存器R14用作连接寄存器,记作IR。用于保存子程序的返回地址,如果在子程序中保存了返回地址,寄存器R14可用于其他用途。
(6)寄存器R15是程序计数器,记作PC。不能用作其他用途。

3.2.NEON寄存器使用规则

(1)NEON S16-S31(D8-D15,Q4-Q7)寄存器在子程序中必须保存,S0-S15(D0-D7,Q4-Q7)和Q8-Q15在子程序中无须保存

3.3.子程序返回寄存器使用规则
(1)结果为一个32位整数时,可以通过寄存器R0返回。
(2)结果为一个64位整数时,可通过寄存器R0和R1返回,依次类推。
(3)结果为一个浮点数时,可以通过浮点运算部件的寄存器F0、D0或者S0来返回。
(4)结果为复合型的浮点数时,可以通过寄存器F0-Fn或者D0-Dn返回。
(5)对于位数更多的结果,需要内存来传递。

3.优化代码

PLD为arm预加载执行的宏定义,下面汇编编写的函数中都使用到了。

    #if 1#define PLD(code...)    code#else#define PLD(code...)#endif

3.1.memcpy_libc

memcpy_libc为libc的库函数memcpy。

3.2.memcpy_1

一次循环只拷贝一个字节,可用于对齐拷贝和非对齐拷贝。

    void *memcpy_1(void *dest, const void *src, size_t count){char *tmp = dest;const char *s = src;while (count--)*tmp++ = *s++;return dest;}

3.3.memcpy_32

memcpy_32一次循环拷贝32字节,适用于32字节对齐拷贝。

    @ void* memcpy_32(void*, const void*, size_t);@ 声明符号为全局作用域.global memcpy_32@ 4字节对齐.align 4@ 声明memcpy_32类型为函数.type memcpy_32, %functionmemcpy_32:@ r4-r12, lr寄存器入栈push        {r4-r11, lr}@ memcpy的返回值为目标存储区域的首地址,即第一个参数值,将返回值保存到r3寄存器中mov         r3, r00:@ 数据预取指令,会将数据提前加载到cache中PLD( pld  [r1, #128] )@ r2为memcpy的第3个参数,表示拷贝多少个字节数,首先减去32,@ s:决定指令的操作是否影响CPSR的值subs        r2, r2, #32@ r1为memcpy的第2个参数,表示源数据的地址,将源地址中的数据加载到r4-r11寄存器中@ 每加载一个寄存器,r1中的地址增加4,总共8个寄存器,共32字节数据ldmia       r1!, {r4-r11}@ 将r4-r11中保存的源数据加载到r1寄存器指向的内存地址,每加载一个寄存器,r1指向的地址加4stmia       r0!, {r4-r11}@stmia       r0!, {r8-r11}@ gt为条件码,带符号数大于,Z=0且N=Vbgt         0b@ 函数退出时将返回值保存到r0中mov         r0, r3pop         {r4-r11, pc}.type memcpy_32, %function@函数体的大小,.-memcpy_32中的.代表当前指令的地址,@即点.减去标号memcpy_32,标号代表当前指令的地址.size memcpy_32, .-memcpy_32

3.4.memcpy_64

memcpy_64一次循环拷贝64字节,适用于64字节对齐拷贝。

    @ void* memcpy_64(void*, const void*, size_t);.global memcpy_64.align 4.type memcpy_64, %functionmemcpy_64:push        {r4-r11, lr}mov         r3, r00:PLD( pld  [r1, #256] )subs        r2, r2, #64ldmia       r1!, {r4-r11}PLD( pld  [r1, #256] )stmia       r0!, {r4-r7}stmia       r0!, {r8-r11}ldmia       r1!, {r4-r11}stmia       r0!, {r4-r7}stmia       r0!, {r8-r11}bgt         0bmov         r0, r3pop         {r4-r11, pc}.type memcpy_64, %function.size memcpy_64, .-memcpy_64

3.5.memcpy_gen

memcpy_gen是通用的内存拷贝函数,可根据源地址和目的地址是否对齐,采用不同的拷贝方法,适用于对齐和非对齐拷贝。此代码参考自Linux内核。
(1)判断拷贝的字节数是否小于4字节,若小于4字节,则直接进行单字节拷贝
(2)判断目的地址是否时按4字节对齐,若没有,则进入目的地址未对齐的处理逻辑
(3)判断源地址是否按4字节对齐,若没有,则进入源地址未对齐的处理逻辑
(4)若目的地址和源地址按4字节对齐,则进入目的地址和源地址对齐的处理逻辑
目的地址和源地址对齐的处理逻辑:
(1)若拷贝的字节数大于等于32字节,则将超过32字节的数据进行批量拷贝,每次拷贝32字节
(2)若剩下的数据小于32字节,则进行4字节拷贝
(3)若剩下的数据小于4字节,则进行单字节拷贝
目的地址未对齐的处理逻辑:
(1)先将未对齐的字节进行单字节拷贝,使目的地址按4字节对齐
(2)若剩余的数据小于4字节,则进行单字节拷贝
(3)此时若源地址也按4字节对齐,则进入目的地址和源地址对齐的处理逻辑
(4)若源地址未按4字节对齐,则进入源地址未对齐的处理逻辑
源地址未对齐的处理逻辑:
(1)将源地址中的数据加载的寄存器中,进行逻辑移位
(2)将低地址的源数据逻辑左移,移到寄存器的低位,将高地址的数据逻辑右移,移到寄存器的高位
(3)将两个寄存器的数据进行或操作,实现了低地址和高地址数据在寄存器中的拼接
(4)将拼接的数据加载到目的地址中

 #define LDR1W_SHIFT 0#define STR1W_SHIFT    0#if __BYTE_ORDER == __BIG_ENDIAN  // 大端#define lspull          lsl#define lspush          lsr#elif __BYTE_ORDER == __LITTLE_ENDIAN // 小端,一般都是小端#define lspull          lsr#define lspush          lsl#else#error "unknow byte order"#endif.macro ldr1w ptr reg abortldr \reg, [\ptr], #4.endm.macro ldr4w ptr reg1 reg2 reg3 reg4 abortldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}.endm.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abortldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}.endm.macro ldr1b ptr reg cond=al abortldr\cond\()b \reg, [\ptr], #1.endm.macro str1w ptr reg abortstr \reg, [\ptr], #4.endm.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abortstmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}.endm.macro str1b ptr reg cond=al abortstr\cond\()b \reg, [\ptr], #1.endm.macro enter reg1 reg2stmdb sp!, {r0, \reg1, \reg2}.endm.macro exit reg1 reg2ldmfd sp!, {r0, \reg1, \reg2}.endm@ void* memcpy_gen(void*, const void*, size_t);@ 声明符号为全局作用域.global memcpy_gen@ 4字节对齐.align 4@ 声明memcpy_gen类型为函数.type memcpy_gen, %functionmemcpy_gen:@ 将r0 r4 lr寄存器保存到栈中,r0是函数的返回值enter  r4, lr@ 拷贝的字节数减4并保存到r2中,运算结果影响CPSR中的标志位subs r2, r2, #4@ blt:带符号数小于@ 如果拷贝的字节数小于4,则跳转到标号8处blt 8f@ r0保存的是目的地址,r0和3与,判断r0的低两位是否是0,不是0,则是未对齐的地址@ s:决定指令的操作是否影响CPSR的值ands    ip, r0, #3  @ 测试目的地址是否是按4字节对齐PLD( pld  [r1, #0] )bne   9f  @ 目的地址没有按4字节对齐,则跳转到标号9处ands ip, r1, #3  @ 测试源地址是否是按4字节对齐bne    10f  @ 源地址没有按4字节对齐,则跳转到标号10处1:  subs    r2, r2, #(28)stmfd  sp!, {r5 - r8}blt   5fPLD( pld  [r1, #0] )2:    subs    r2, r2, #96PLD( pld  [r1, #28] )blt 4fPLD( pld  [r1, #60] )PLD( pld  [r1, #92] )3:  PLD( pld  [r1, #124] )4:    ldr8w   r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20fsubs  r2, r2, #32str8w    r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20fbge   3bcmn   r2, #96bge  4b5:    ands    ip, r2, #28rsb  ip, ip, #32#if LDR1W_SHIFT > 0lsl    ip, ip, #LDR1W_SHIFT#endifaddne pc, pc, ip      @ C is always clear hereb  7f6:@ .rept:重复定义伪操作, 格式如下:@ .rept     重复次数@ 数据定义@ .endr     结束重复定义@ 例如:@  .rept 3@  .byte 0x23@  .endr.rept (1 << LDR1W_SHIFT)nop.endrldr1w   r1, r3, abort=20fldr1w r1, r4, abort=20fldr1w r1, r5, abort=20fldr1w r1, r6, abort=20fldr1w r1, r7, abort=20fldr1w r1, r8, abort=20fldr1w r1, lr, abort=20f#if LDR1W_SHIFT < STR1W_SHIFTlsl   ip, ip, #STR1W_SHIFT - LDR1W_SHIFT#elif LDR1W_SHIFT > STR1W_SHIFTlsr ip, ip, #LDR1W_SHIFT - STR1W_SHIFT#endifadd pc, pc, ipnop.rept  (1 << STR1W_SHIFT)nop.endrstr1w   r0, r3, abort=20fstr1w r0, r4, abort=20fstr1w r0, r5, abort=20fstr1w r0, r6, abort=20fstr1w r0, r7, abort=20fstr1w r0, r8, abort=20fstr1w r0, lr, abort=20f7:    ldmfd   sp!, {r5 - r8}8:    @ 处理拷贝的字节数小于4字节,此时r2中的值为负数,可能取值为-1 -2 -3@ lsl 逻辑左移,将r2左移31位保存带r2中movs    r2, r2, lsl #31@ ne 不相等,Z=0,r2为-1或-3时拷贝数据ldr1b  r1, r3, ne, abort=21f@ cs 无符号数大于等于,C=1@ 对于包含移位操作的非加/减法运算指令,C中包含最后一次被溢出的位的数值ldr1b  r1, r4, cs, abort=21fldr1b r1, ip, cs, abort=21fstr1b r0, r3, ne, abort=21fstr1b r0, r4, cs, abort=21fstr1b r0, ip, cs, abort=21fexit  r4, pc9:  @ 处理目的地址未按4字节对齐的情况@ rsb 逆向减法指令,等价于ip=4-ip,同时根据操作结果更新CPSR中相应的条件标志@ 当rsb的运算结果为负数时,N=1,为正数或0时,N=0@ 当rsb的运算结果符号位溢出时,V=1rsb  ip, ip, #4  @ 当地址不按4字节对齐的时候,ip的值取值可能为1、2、3@ 对于cmp指令,Z=1表示进行比较的两个数大小相等cmp   ip, #2  @ cmp影响@ gt:带符号数大于,Z=0且N=Vldr1b   r1, r3, gt, abort=21f  @ ip为3时将数据加载到r3寄存器中,同时r1=r1+1@ ge:带符号数大于等于,N=1且V=1或N=0且V=0ldr1b    r1, r4, ge, abort=21f  @ ip为2时将数据加载到r4寄存器中,同时r1=r1+1ldr1b    r1, lr, abort=21f      @ ip为1时将数据加载到lr寄存器中,同时r1=r1+1str1b    r0, r3, gt, abort=21fstr1b r0, r4, ge, abort=21fsubs  r2, r2, ip  @ 更新拷贝的字节数str1b    r0, lr, abort=21f@ 带符号数小于,N=1且V=0或N=0且V=1blt   8bands  ip, r1, #3  @ 测试源地址是否是4字节对齐的情况@ eq 相等,Z=1,r1中的地址已按4字节对齐,则跳转到标号1处,否则继续向下执行beq 1b10:   @ 处理源地址未按4字节对齐的情况@ bic指令用于清除操作数1的某些位,并把结果放置到目的寄存器中@ 将r1的低2位清0bic  r1, r1, #3@ ip保存了r1的低两位,源地址的低2位与2比较cmp  ip, #2@ 无条件执行,将r1寄存器指向的4字节数据加载到lr寄存器中,拷贝完r1=r1+4ldr1w  r1, lr, abort=21f@ eq 相等,Z=1@ ip寄存器和2相等beq   17f@ gt:带符号数大于,Z=0且N=V@ ip寄存器大于2bgt   18f.macro   forward_copy_shift pull push@ r2寄存器减去28subs    r2, r2, #28@ 带符号数小于,N=1且V=0或N=0且V=1,r2小于28跳转到14处blt  14f11:  @ 保存r5-r9寄存器,同时更新sp寄存器,fd:满递减stmfd    sp!, {r5 - r9}PLD( pld  [r1, #0] )subs  r2, r2, #96  @ r2减去96PLD( pld  [r1, #28] )blt  13f  @ 带符号数小于,N=1且V=0或N=0且V=1,r2小于96跳转到13处PLD( pld  [r1, #60] )PLD( pld  [r1, #92] )12:  PLD( pld  [r1, #124] )13:   @ lspull(小端) = lsr:逻辑右移@ lspush(小端) = lsr:逻辑左移ldr4w   r1, r4, r5, r6, r7, abort=19f@ lr逻辑右移pull位并存储到r3寄存器中mov   r3, lr, lspull #\pullsubs   r2, r2, #32ldr4w    r1, r8, r9, ip, lr, abort=19f@ r4逻辑左移push位,然后和r3或,最后将结果保存到r3中@ 将r4的push位保存到r3的(32-push)位orr    r3, r3, r4, lspush #\pushmov    r4, r4, lspull #\pullorr    r4, r4, r5, lspush #\pushmov    r5, r5, lspull #\pullorr    r5, r5, r6, lspush #\pushmov    r6, r6, lspull #\pullorr    r6, r6, r7, lspush #\pushmov    r7, r7, lspull #\pullorr    r7, r7, r8, lspush #\pushmov    r8, r8, lspull #\pullorr    r8, r8, r9, lspush #\pushmov    r9, r9, lspull #\pullorr    r9, r9, ip, lspush #\pushmov    ip, ip, lspull #\pullorr    ip, ip, lr, lspush #\pushstr8w  r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19fbge 12bcmn  r2, #96bge  13bldmfd    sp!, {r5 - r9}14:   ands    ip, r2, #28beq  16f15:  mov r3, lr, lspull #\pullldr1w  r1, lr, abort=21fsubs  ip, ip, #4orr   r3, r3, lr, lspush #\pushstr1w  r0, r3, abort=21fbgt   15b16:  sub r1, r1, #(\push / 8)b   8b.endmforward_copy_shift   pull=8 push=2417: forward_copy_shift  pull=16    push=1618: forward_copy_shift  pull=24    push=8.macro   copy_abort_preamble19:  ldmfd   sp!, {r5 - r9}b 21f20:  ldmfd   sp!, {r5 - r8}21:.endm.macro    copy_abort_endldmfd sp!, {r4, pc}.endm.type memcpy_gen, %function@函数体的大小,.-memcpy_gen中的.代表当前指令的地址,@即点.减去标号memcpy_gen,标号代表当前指令的地址.size memcpy_gen, .-memcpy_gen

3.7.memcpy_neon_128

memcpy_neon_128使用NEON寄存器进行加速拷贝,一次拷贝128字节,适用于128字节的对齐拷贝。

    @ void* memcpy_neon_128(void*, const void*, size_t);@ 声明符号为全局作用域.global memcpy_neon_128@ 4字节对齐.align 4@ 声明memcpy_neno类型为函数.type memcpy_neon_128, %functionmemcpy_neon_128:@ 保存neon寄存器vpush.64 {d8-d15}@ 保存返回值mov       r3, r00:PLD( pld  [r1, #512] )  subs    r2,  r2, #128vldmia.64  r1!,  {d0-d15}vstmia.64  r0!,  {d0-d15}bgt     0b@ 函数退出时将返回值保存到r0中mov      r0, r3vpop.64 {d8-d15}@ 将函数的返回地址保存搭配pc中,退出函数mov     pc, lr .type memcpy_neon_128, %function@函数体的大小,.-memcpy_neon_128中的.代表当前指令的地址,@即点.减去标号memcpy_neon_128,标号代表当前指令的地址.size memcpy_neon_128, .-memcpy_neon_128

3.速度测试

3.1.对齐拷贝测试(单位:MiB/s)

3.2.非对齐拷贝测试(单位:MiB/s)

4.影响拷贝速度的因素

(1)一次循环拷贝数据的字节数
(2)地址是否对齐
(3)pld预取对uncache拷贝影响很小

5.结论

(1)大批量数据拷贝时,应将源地址和目的地址按32字节、64字节或128字节对齐
(2)按32字节、64字节或128字节对齐的数据,使用neon寄存器进行批量拷贝,若无neon寄存器,则使用arm寄存器进行批量拷贝
(3)若拷贝的字节数小于要求的字节数,则使用通用的方法进行拷贝
(4)uncache区域拷贝,预加载pld指令对拷贝速度的提升有限

Linux内核memcpy的不同实现相关推荐

  1. linux内核编程memcpy,memcpy Linux内核实现引发的思考:为什么嵌入式汇编中不用指定段寄存器...

    memcpy Linux内核实现引发的思考:为什么嵌入式汇编中不用指定段寄存器 (2013-05-18 18:42:25) 标签: 内核 汇编 指定 杂谈 memcpy Linux内核实现引发的思考: ...

  2. Linux内核网络栈1.2.13-icmp.c概述

    参考资料 <<linux内核网络栈源代码情景分析>> icmp协议 在实现的过程中, ICMP协议工作再IP协议之上,但又不与TCP协议工作再一级,而是在下一级,在一般ICMP ...

  3. Linux内核网络栈1.2.13-tcp.c概述

    参考资料 <<linux内核网络栈源代码情景分析>> af_inet.c文件中调用函数在协议层的实现 本文主要根据在af_inet.c文件中根据初始化不同的协议,来调用不同的协 ...

  4. Linux内核源代码分析-第三章 内核体系结构概述-3

    3.5 设计和实现的关系 接下来的部分将介绍一些内核设计和实现之间的关系.本部分最重要的内容是对于内核源 程序目录结构的概述,这一点随后就会提到.本章最后以实现中体系结构无关代码和体系 结构相关代码的 ...

  5. Linux内核源代码情景分析-fork()

    父进程fork子进程: child = fork() fork经过系统调用.来到了sys_fork.具体过程请參考Linux内核源码情景分析-系统调用. asmlinkage int sys_fork ...

  6. 2018-2019-1 20189204《Linux内核原理与分析》第三周作业

    OS是如何工作的 学习任务: 阅读学习教材「庖丁解牛Linux 」第2章 学习蓝墨云班课中第三周视频「操作系统是如何工作的?」,并完成实验楼上配套实验二. 云班课学习笔记: 计算机三大法宝 程序存储计 ...

  7. linux内核中的每cpu变量

    一.linux中的每cpu变量 看linux内核代码的时候,会发现大量的per_cpu(name, cpu),get_cpu_var(name)等出现cpu字眼的语句.从语句的意思可以看出是要使用与当 ...

  8. linux 内核与用户空间通信之netlink使用方法

    Linux中的进程间通信机制源自于Unix平台上的进程通信机制.Unix的两大分支AT&T Unix和BSD Unix在进程通信实现机制上的各有所不同,前者形成了运行在单个计算机上的Syste ...

  9. linux 内核网络协议栈

    Linux网络协议栈之数据包处理过程  1前言 本来是想翻译<The journey of a packet through the linux 2.4 network stack>这篇文 ...

  10. Linux内核网络协议栈

    一.注册时机 1.在内核初始化时完成: 2.内核初始化过程(init/main.c):kernel_init()->do_basic_setup()->do_initcalls()-> ...

最新文章

  1. 使用Spring Boot和RxJava的构建响应式REST API
  2. java课设电子门禁_Door门禁系统.doc
  3. js,jquery获取页面元素距离浏览器工作区顶端的距离
  4. ACM公选第六节下DP基础(当复习了)2020.4.16-5.10补
  5. visual studio 设计器不显示_面向国际市场的装置开发运维软件设计与实现
  6. 10分钟搭建完成人脸通行系统 百度『乘风』人脸智能化平台了解一下
  7. 简单批处理与多道批处理
  8. USACO 2.33 Zero Sum
  9. poj 2389 Bull Math java解决!!
  10. 冒险岛(MapleStory) × Re:从零开始的异世界生活 游戏联动人物素材(含提取方法)
  11. 数字化转型、智能制造、工业软件及其应用案例资源列表
  12. cmd命令把GHO转换成虚拟机可直接加载的硬盘格式实例
  13. 【Tomcat】Tomcat 介绍及使用教程
  14. 中国本土八大会计师事务所简介
  15. 网站百度竞价有展现,点击无咨询原因
  16. 一个人的“野蛮”战争——周鸿祎奋斗记
  17. hxxp://www.hao923.com.cn/劫持浏览器
  18. 轮播图展示与轮播图管理
  19. win10平板续航测试软件,Win10平板必备工具!触摸屏虚拟鼠标应用推荐
  20. vue项目中扫码枪收款

热门文章

  1. Python算法、经典面试常见案例题大分享!!!
  2. [ openwrt ] 添加一个通过GPIO控制的LED
  3. Dubbo视频教程--基础篇--第03节--ZooKeeper注册中心安装详细步骤(单节点)
  4. ISO50001认证咨询,企业申请ISO50001认证前要先进行哪些初始能源评审
  5. python黑帽子怎么样_PYTHON 黑帽子第二章总结
  6. MemReduct内存自动清理工具
  7. 【学生网页设计作业源码】基于HTML+CSS+JavaScript简单的大学生书店(13个页面) 二手书店电子商务网站模板源码
  8. Matlab报错 :“位置 x 处的索引超出数组边界”
  9. UWB超宽带定位技术
  10. 苹果CMSv10自适应短视频原创挖片网高端手机+电脑模板