时钟中断处理程序--do_timer()

来源:互联网 发布:淘宝装修950全屏教程 编辑:程序博客网 时间:2024/05/04 13:08
start_kernel()

--void timer_tick(void)  

//为Kernel提供的体系架构无关的、系统相关的时钟中断处理函数,通常会在体系架构相关的时钟中断处理函数内调用它。参考1;

{
    profile_tick(CPU_PROFILING);//调用profile_tick()监管内核代码
    do_leds();
    write_seqlock(&xtime_lock);
    do_timer(1);//在do_timer()中增加jiffies_64值和调用update_times()更新系统日期和时间
    write_sequnlock(&xtime_lock);
#ifndef CONFIG_SMP
    update_process_times(user_mode(get_irq_regs()));
#endif
}

----update_process_times(user_mode(get_irq_regs()))

+-----------------------------------------------------------------------------------------

#define user_mode(regs)    \
    (((regs)->ARM_cpsr & 0xf) == 0)

++-----------------------------------------------------------------------------------------
static inline struct pt_regs *get_irq_regs(void)
{
    return __this_cpu_read(__irq_regs);

}

+++-----------------------------------------------------------------------------------------

DECLARE_PER_CPU(struct pt_regs *, __irq_regs);

//这个宏的最终目的是定义了一个结构体指针__irq_regs,这个指针指向pt_regs类型结构体,这个指针是每CPU类型的,

//即每个CPU拥有一个这样的指针并指向相应的pt_regs结构体;并且这个指针被保存在名为“data..percpu”的输入段中

++++-----------------------------------------------------------------------------------------

#define DECLARE_PER_CPU(type, name)                    \
    DECLARE_PER_CPU_SECTION(type, name, "")

//DECLARE_PER_CPU(struct pt_regs *, __irq_regs);被展开为

//===========> DECLARE_PER_CPU_SECTION(struct pt_regs *, __irq_regs, "")

+++++-----------------------------------------------------------------------------------------

#define DECLARE_PER_CPU_SECTION(type, name, sec)            \
    extern __PCPU_ATTRS(sec) __typeof__(type) name

//传入的sec为空,DECLARE_PER_CPU(struct pt_regs *, __irq_regs);被展开为

//===========>extern __PCPU_ATTRS(sec) __typeof__(struct pt_regs *) __irq_regs

++++++-----------------------------------------------------------------------------------------

#define __PCPU_ATTRS(sec)                        \
    __percpu __attribute__((section(PER_CPU_BASE_SECTION sec)))    \
    PER_CPU_ATTRIBUTES

//参考gcc的__attribute__编译属

//DECLARE_PER_CPU(struct pt_regs *, __irq_regs);被展开为

//============>extern __percpu __attribute__((section(PER_CPU_BASE_SECTION)))    \
//    PER_CPU_ATTRIBUTES __typeof__(struct pt_regs *) __irq_regs

+++++++-----------------------------------------------------------------------------------------

# define __percpu    __attribute__((noderef, address_space(3)))

//参考下文说明

+++++++-----------------------------------------------------------------------------------------

#define PER_CPU_BASE_SECTION ".data..percpu"

+++-----------------------------------------------------------------------------------------

最终DECLARE_PER_CPU(struct pt_regs *, __irq_regs);被展开为

=============>extern __percpu __attribute__((section(.data..percpu)))    \
    PER_CPU_ATTRIBUTES __typeof__(struct pt_regs *) __irq_regs

其中PER_CPU_ATTRIBUTES为空,可能是做内核扩展时用的,发现在3.0.9内核中只有定义

#ifdef HAVE_MODEL_SMALL_ATTRIBUTE
# define PER_CPU_ATTRIBUTES    __attribute__((__model__ (__small__)))
#endif

=============>extern __percpu __attribute__((section(.data..percpu)))    \
    __typeof__(struct pt_regs *) __irq_regs

其中__percpu限制__irq_regs是每CPU地址空间变量,

__attribute__((section("section_name"))) 其作用是将作用的函数或数据放入指定名为"section_name"输入段。

所以这个宏的最终目的是定义了一个结构体指针__irq_regs,这个指针指向pt_regs类型结构体,这个指针是每CPU类型的,

即每个CPU拥有一个这样的指针并指向相应的pt_regs结构体;并且这个指针被保存在名为“data..percpu”的输入段中

关于输入段和输入段的解释参考下面的链接

//详细参考gcc的__attribute__编译属

+++-----------------------------------------------------------------------------------------

# define __this_cpu_read(pcp)    __pcpu_size_call_return(__this_cpu_read_, (pcp))

++++-----------------------------------------------------------------------------------------

#define __pcpu_size_call_return(stem, variable)                \
({    typeof(variable) pscr_ret__;                    \
    __verify_pcpu_ptr(&(variable));                    \
    switch(sizeof(variable)) {                    \
    case 1: pscr_ret__ = stem##1(variable);break;            \
    case 2: pscr_ret__ =stem##2(variable);break;            \
    case 4: pscr_ret__ = stem##4(variable);break;            \
    case 8: pscr_ret__ =stem##8(variable);break;            \
    default:                            \
        __bad_size_call_parameter();break;            \
    }                                \
    pscr_ret__;                            \
})

//展开__this_cpu_read(__irq_regs)

//=========>

({    typeof(__irq_regs) pscr_ret__;                    \
    __verify_pcpu_ptr(&(__irq_regs));                    \
    switch(sizeof(__irq_regs)) {                    \
    case 1: pscr_ret__ = __this_cpu_read_1(__irq_regs);break;            \
    case 2: pscr_ret__ = __this_cpu_read_2(__irq_regs);break;            \
    case 4: pscr_ret__ = __this_cpu_read_4(__irq_regs);break;            \
    case 8: pscr_ret__ = __this_cpu_read_8(__irq_regs);break;            \
    default:                            \
        __bad_size_call_parameter();break;            \
    }                                \
    pscr_ret__;                            \
})

//typeof是gcc对C语言的一个扩展保留字,用于声明变量类型,比方说:
//typeof(int   *)   p;
//声明p为一个int类型的指针
//typeof(*x)   p;
//声明p为x所指向的类型

//pscr_ret__是variable类型

参考:http://topic.csdn.net/t/20030715/13/2030100.html


+++++-----------------------------------------------------------------------------------------

#  define __this_cpu_read_n(pcp)    (*__this_cpu_ptr(&(pcp)));

++++++-----------------------------------------------------------------------------------------

#define __this_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, __my_cpu_offset)

+++++++-----------------------------------------------------------------------------------------

#define __my_cpu_offset per_cpu_offset(raw_smp_processor_id())

++++++++-----------------------------------------------------------------------------------------

#ifndef __per_cpu_offset
extern unsigned long __per_cpu_offset[NR_CPUS];    //__per_cpu_offset一个无符号长整形数组,数组元素个数就是CPU个数,用来计算SMP每个CPU的数据段地址。

#define per_cpu_offset(x) (__per_cpu_offset[x])
#endif

在该函数中,为每个CPU分配一段专有数据区,并将.data.percpu中的数据拷
贝到其中,每个CPU各有一份。由于数据从__per_cpu_start处转移到各CPU自己的专有
数据区中了,因此存取其中的变量就不能再用原先的值了,比如存取
per_cpu__runqueues就不能再用per_cpu__runqueues了,需要做一个偏移量的调整,即
需要加上各CPU自己的专有数据区首地址相对于__per_cpu_start的偏移量。在这里也就
是__per_cpu_offset[i],其中CPU i的专有数据区相对于
__per_cpu_start的偏移量为__per_cpu_offset[i]。这样,就可以方便地计算专有数据
区中各变量的新地址,比如对于per_cpu_runqueues,其新地址即变成
per_cpu_runqueues+__per_cpu_offset[i]。

参考:多处理器体系中cpu私有数据的重定位(即per_cpu)

+++++++++-----------------------------------------------------------------------------------------

#define NR_CPUS        CONFIG_NR_CPUS

//CONFIG_NR_CPUS是内核被配置支持的CPU个数,而实际设备的CPU个数是在系统启动过程当中去动态监测的。也就是说你配置系统支持32个CPU那么CONFIG_NR_CPUS就等于32,而num_online_cpus()则是当前设备激活可调度的CPU个数。

参考:关于NR_CPUS的疑惑

+++++++-----------------------------------------------------------------------------------------

#define SHIFT_PERCPU_PTR(__p, __offset)    ({                \
    __verify_pcpu_ptr((__p));                    \
    RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset)); \
})

//最后展开为

({                \
    __verify_pcpu_ptr((__p));                    \
    RELOC_HIDE((typeof(__irq_regs) __kernel __force *)(&(__irq_regs)), (__offset)); \
})

+++++-----------------------------------------------------------------------------------------


#define __verify_pcpu_ptr(ptr)    do {                    \
    const void __percpu *__vpp_verify = (typeof(ptr))NULL;        \
    (void)__vpp_verify;                        \
} while (0)

//这个宏用来验证(*ptr)是否是percpu类型指针

参考:设置每CPU环境

++++++-----------------------------------------------------------------------------------------

# define __percpu    __attribute__((noderef, address_space(3)))

//一种修饰变量、类型或者函数的属性,用来修饰一个变量时,这个变量必须是非解除参考(no dereference)的,即这个变量地址必须是有效的,而且变量所在的地址空间类型必须是0~3,0:normal space内核空间;1:用户空间;2:设备地址映射空间;3:smp时每个cpu的地址空间;4:rcu地址空间。

参考:/include/linux/compiler.h

参考:sparse 工具的介绍及简单应用

参考:GNU C 扩展之__attribute__ 机制简介(转)

参考:# define __user __attribute__((noderef, address_space(1)))

参考:(ZT)GNU C 的 __attribute__ 机制

+++-----------------------------------------------------------------------------------------

struct pt_regs {
    unsigned long uregs[18];
}

//存放CPU运行环境

++++-----------------------------------------------------------------------------------------

#define ARM_cpsr    uregs[16]
#define ARM_pc        uregs[15]
#define ARM_lr        uregs[14]
#define ARM_sp        uregs[13]
#define ARM_ip        uregs[12]
#define ARM_fp        uregs[11]
#define ARM_r10        uregs[10]
#define ARM_r9        uregs[9]
#define ARM_r8        uregs[8]
#define ARM_r7        uregs[7]
#define ARM_r6        uregs[6]
#define ARM_r5        uregs[5]
#define ARM_r4        uregs[4]
#define ARM_r3        uregs[3]
#define ARM_r2        uregs[2]
#define ARM_r1        uregs[1]
#define ARM_r0        uregs[0]
#define ARM_ORIG_r0    uregs[17]

参考:http://www.hackvip.com/article/sort0136/sort0186/Hackvip_184477.html

价值文档:linux 时钟处理机制

原创粉丝点击