从函数指针调用函数而不分配?

时间:2012-04-04 07:46:48

标签: c linux linux-kernel kernel

通常我们必须这样做以从函数指针调用函数:

int foo()
{
}

int main()
{
    int (*pFoo)() = foo; // pFoo points to function foo()
    foo();
    return 0;
}

在Linux内核代码中,sched_class有许多函数指针:

struct sched_class {
        const struct sched_class *next;

        void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);
        void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);
        void (*yield_task) (struct rq *rq);
        bool (*yield_to_task) (struct rq *rq, struct task_struct *p, bool preempt);
        .....
}

pick_next_task函数中,它定义了名为sched_class的{​​{1}}的本地实例,并直接调用其中的函数,而不分配具有相同签名的外部函数(从{{开始) 1}}):

class

这是因为for_each_class中的每个函数指针都与实际实现的函数具有相同的名称,因此每次通过static inline struct task_struct * pick_next_task(struct rq *rq) { const struct sched_class *class; struct task_struct *p; /* * Optimization: we know that if all tasks are in * the fair class we can call that function directly: */ if (likely(rq->nr_running == rq->cfs.h_nr_running)) { p = fair_sched_class.pick_next_task(rq); if (likely(p)) return p; } for_each_class(class) { p = class->pick_next_task(rq); if (p) return p; } BUG(); /* the idle class will always have a runnable task */ } 的函数指针进行调用时,它都会自动找到匹配内核地址空间中的符号?

3 个答案:

答案 0 :(得分:5)

for_each_class的定义应该为您清除

 #define for_each_class(class) \
       for (class = sched_class_highest; class; class = class->next)

如果你继续跟踪,sched_class_highest将结束这样的事情

#define sched_class_highest (&stop_sched_class)
extern const struct sched_class stop_sched_class;

/*
* Simple, special scheduling class for the per-CPU stop tasks:
*/
const struct sched_class stop_sched_class = {
      .next                   = &rt_sched_class,

      .enqueue_task           = enqueue_task_stop,
      .dequeue_task           = dequeue_task_stop,
      .yield_task             = yield_task_stop,

      .check_preempt_curr     = check_preempt_curr_stop,

      .pick_next_task         = pick_next_task_stop,
      .put_prev_task          = put_prev_task_stop,

#ifdef CONFIG_SMP
      .select_task_rq         = select_task_rq_stop,
#endif

     .set_curr_task          = set_curr_task_stop,
     .task_tick              = task_tick_stop,

     .get_rr_interval        = get_rr_interval_stop,

     .prio_changed           = prio_changed_stop,
     .switched_to            = switched_to_stop,
};

现在你快乐吗? :)

答案 1 :(得分:2)

https://github.com/torvalds/linux/blob/v3.3/kernel/sched/sched.h#L850

查看for_each_class宏的扩展。它在使用之前为class指针赋值。

答案 2 :(得分:0)

每个sched_class结构及其包含的函数指针都被初始化(否则,它可能是一个错误)。例如,公平计划class已在kernel/sched/fair.c中初始化(请参阅here):

const struct sched_class fair_sched_class = {
        .next                   = &idle_sched_class,
        /* lots of assignments */
        .pick_next_task         = pick_next_task_fair,
        /* etc. */
};