0

通常、関数ポインタから関数を呼び出すには、次のようにする必要があります。

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関数では、 namedローカル インスタンスを定義し、同じシグネチャ ( から開始)を持つ外部関数に割り当てずに、その関数を直接呼び出します。sched_classclassfor_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 */
}

これは、 の各関数ポインタがsched_class実際に実装された関数と同じ名前を持っているため、 の関数ポインタを介して呼び出しが行われるたびsched_classに、カーネル アドレス空間で一致するシンボルが自動的に検出されるためですか?

4

3 に答える 3

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,
};

今、あなたは幸せですか?:)

于 2012-04-04T07:50:56.747 に答える
2

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

for_each_classマクロの展開を見てください。ポインターを使用する前に、ポインターに値を割り当てますclass

于 2012-04-04T07:50:42.980 に答える
0

sched_class構造体とそこに含まれる関数ポインタが初期化されます (それ以外の場合は、おそらくバグです)。たとえば、フェア スケジューリングクラスは次のように初期化されますkernel/sched/fair.c(こちらを参照)。

const struct sched_class fair_sched_class = {
        .next                   = &idle_sched_class,
        /* lots of assignments */
        .pick_next_task         = pick_next_task_fair,
        /* etc. */
};
于 2012-04-04T07:55:07.573 に答える