时钟三

时钟机制的,使用通知链技术来执行。

通知链技术,时钟源建立一个链表,然后待发生的事件将自己要执行的操作注册到链表上,简单吧,呵呵

通知链有好多种:

  • 原子通知链( Atomic notifier chains ):通知链元素的回调函数(当事件发生时要执行的函数)只能在中断上下文中运行,不允许阻塞
  • 可阻塞通知链( Blocking notifier chains ):通知链元素的回调函数在进程上下文中运行,允许阻塞
  • 原始通知链( Raw notifier chains ):对通知链元素的回调函数没有任何限制,所有锁和保护机制都由调用者维护
  • SRCU 通知链( SRCU notifier chains ):可阻塞通知链的一种变体
    所以对应了四种通知链头结构:
    • struct atomic_notifier_head :原子通知链的链头
    • struct blocking_notifier_head :可阻塞通知链的链头
    • struct raw_notifier_head :原始通知链的链头
    • struct srcu_notifier_head : SRCU 通知链的链头

    通知链元素的类型:
    • struct notifier_block :通知链中的元素,记录了当发出通知时,应该执行的操作(即回调函数)

    先贴tick_init  //向通知链中注册回调函数

    kernel/time/tick-common.c

    /**
     * tick_init - initialize the tick control
     *
     * Register the notifier with the clockevents framework
     */
    void __init tick_init(void)
    {
            clockevents_register_notifier(&tick_notifier);   //向通知链中注册元素
    }

    kernel/time/clockevents.c

    static RAW_NOTIFIER_HEAD(clockevents_chain);   //此链表维护了将要执行的事件操作

    int clockevents_register_notifier(struct notifier_block *nb)
    {
            unsigned long flags;
            int ret;

            spin_lock_irqsave(&clockevents_lock, flags);
            ret = raw_notifier_chain_register(&clockevents_chain, nb);
            spin_unlock_irqrestore(&clockevents_lock, flags);

            return ret;
    }


    static struct notifier_block tick_notifier = {   //回调函数
            .notifier_call = tick_notify,
    };
    /*
     * Notification about clock event devices
     */
    static int tick_notify(struct notifier_block *nb, unsigned long reason,
                                   void *dev)
    {
            switch (reason) {

            case CLOCK_EVT_NOTIFY_ADD:
                    return tick_check_new_device(dev);

            case CLOCK_EVT_NOTIFY_BROADCAST_ON:
            case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
            case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
                    tick_broadcast_on_off(reason, dev);
                    break

            case CLOCK_EVT_NOTIFY_BROADCAST_ENTER:
            case CLOCK_EVT_NOTIFY_BROADCAST_EXIT:
                    tick_broadcast_oneshot_control(reason);
                    break;

            case CLOCK_EVT_NOTIFY_CPU_DYING:
                    tick_handover_do_timer(dev);
                    break;

            case CLOCK_EVT_NOTIFY_CPU_DEAD:
                    tick_shutdown_broadcast_oneshot(dev);
                    tick_shutdown_broadcast(dev);
                    tick_shutdown(dev);
                    break;

            case CLOCK_EVT_NOTIFY_SUSPEND:
                    tick_suspend();
                    tick_suspend_broadcast();
                    break;

         case CLOCK_EVT_NOTIFY_RESUME:
                    tick_resume();
                    break;

            default:
                    break;
            }

            return NOTIFY_OK;
    }

    该贴init_timers了
    kernel/time/timer.c

    void __init init_timers(void)
    {
            int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
                                    (void *)(long)smp_processor_id()); //首次调用初始化本CPU上的boot_tvec_base

            init_timer_stats();

            BUG_ON(err == NOTIFY_BAD);
            register_cpu_notifier(&timers_nb);   //向CPU通知链注册回调函数定义在kernel/cpu.c中static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);

            open_softirq(TIMER_SOFTIRQ, run_timer_softirq); //初始化软中断函数
    }

    static struct notifier_block __cpuinitdata timers_nb = {   //回调函数
            .notifier_call  = timer_cpu_notify,
    };

    static int __cpuinit timer_cpu_notify(struct notifier_block *self,  //回调函数,首次执行初始化本CPU的boot_tvec_base
                                    unsigned long action, void *hcpu)
    {
            long cpu = (long)hcpu;
            switch(action) {
            case CPU_UP_PREPARE:
            case CPU_UP_PREPARE_FROZEN:
                    if (init_timers_cpu(cpu) < 0)
                            return NOTIFY_BAD;
                    break;
    #ifdef CONFIG_HOTPLUG_CPU
            case CPU_DEAD:
            case CPU_DEAD_FROZEN:
                    migrate_timers(cpu);
                    break;
    #endif
            default:
                    break;
            }
            return NOTIFY_OK;
    }
    static int __cpuinit init_timers_cpu(int cpu)   //初始化本CPU上的boot_tvec_base
    {
            int j;
            struct tvec_base *base;
            static char __cpuinitdata tvec_base_done[NR_CPUS];

            if (!tvec_base_done[cpu]) {
                    static char boot_done;

                    if (boot_done) {
                            /*
                             * The APs use this path later in boot
                             */
                            base = kmalloc_node(sizeof(*base),
                                                    GFP_KERNEL | __GFP_ZERO,
                                                    cpu_to_node(cpu));
                            if (!base)
                                    return -ENOMEM;

                            /* Make sure that tvec_base is 2 byte aligned */
                            if (tbase_get_deferrable(base)) {
                                    WARN_ON(1);

                                    kfree(base);
                                    return -ENOMEM;
                            }
                            per_cpu(tvec_bases, cpu) = base;
                    } else {
                            /*
                             * This is for the boot CPU - we use compile-time
                             * static initialisation because per-cpu memory isn't
                             * ready yet and because the memory allocators are not
                             * initialised either.
                             */
                            boot_done = 1;
                            base = &boot_tvec_bases;
                    }
                    tvec_base_done[cpu] = 1;
            } else {
                    base = per_cpu(tvec_bases, cpu);
            }

            spin_lock_init(&base->lock);

            for (j = 0; j < TVN_SIZE; j++) {

                    INIT_LIST_HEAD(base->tv5.vec + j);
                    INIT_LIST_HEAD(base->tv4.vec + j);
                    INIT_LIST_HEAD(base->tv3.vec + j);
                    INIT_LIST_HEAD(base->tv2.vec + j);
            }
            for (j = 0; j < TVR_SIZE; j++)
                    INIT_LIST_HEAD(base->tv1.vec + j);

            base->timer_jiffies = jiffies;
            return 0;
    }

    void open_softirq(int nr, void (*action)(struct softirq_action *))  //初始化软中断函数
    {
            softirq_vec[nr].action = action;
    }


    这里有必要贴一下struct tvec_base了

    /kernel/timer.c

    struct tvec_base {
            spinlock_t lock;
            struct timer_list *running_timer;
            unsigned long timer_jiffies;
            struct tvec_root tv1;
            struct tvec tv2;
            struct tvec tv3;
            struct tvec tv4;
            struct tvec tv5;
    } ____cacheline_aligned;

    struct tvec {
            struct list_head vec[TVN_SIZE];
    };

     


     

     

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值