Разработка ядра Linux | страница 67



• Функция >load_balance() находит непустой список заданий, соответствующий самому высокому приоритету (с самым маленьким номером), так как важно более равномерно распределять задания с высоким приоритетом, чем с низким.

• Каждое задание с данным приоритетом анализируется для определения задания, которое не выполняется, не запрещено для миграции из-за процессорной привязки и не активно в кэше. Если найдена задача, которая удовлетворяет этому критерию, то вызывается функция >pull_task() для проталкивания этой задачи из наиболее загруженной очереди в данную очередь.

• Пока очереди выполнения остаются разбалансированными, предыдущие два шага повторяются и необходимое количество заданий проталкивается из самой загруженной очереди выполнения в данную очередь выполнения. В конце концов, когда дисбаланс устранен, очередь выполнения разблокируется и происходит возврат из функции >load_balance().

Далее показана функция >load_balance(), немного упрощенная, но содержащая все важные детали.

>static int load_balance(int this_cpu, runqueue_t *this_rq,

> struct sched_domain *sd, enum idle_type idle) {

> struct sched_group *group;

> runqueue_t *busiest;

> unsigned long imbalance;

> int nr_moved;


> spin_lock(&this_rq->lock);


> group = find_busiest_group(sd, this_cpu, &imbalance, idle);

> if (!group)

>  goto out_balanced;

> busiest = find_busiest_queue(group);

> if (!busiest)

>  goto out_balanced;


> nr_moved = 0;

> if (busiest->nr_running > 1) {

>  double_lock_balance(this_rq, busiest);

>  nr_moved = move_tasks(this_rq, this_cpu, busiest,

>   imbalance, sd, idle);

>  spin_unlock(&busiest->lock);

> }

> spin_unlock(&this_rq->lock);


> if (!nr_moved) {

>  sd->nr_balance_failed++;


>  if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) {

>   int wake = 0;


>   spin_lock(&busiest->lock);

>   if (!busiest->active_balance) {

>    busiest->active_balance = 1;

>    busiest->push_cpu = this_cpu;

>    wake = 1;

>   }

>   spin_unlock(&busiest->lock);

>   if (wake)

>    wake_up_process(busiest->migration_thread);

>   sd->nr_balance_failed = sd->cache_nice_tries;

>  }

> } else

>  sd->nr_balance_failed = 0;

> sd->balance_interval = sd->min_interval;

> return nr_moved;

>out_balanced:

> spin_unlock(&this_rq->lock);


> if (sd->balance_interval < sd->max_interval)

>  sd->balance_interval *= 2;


> return 0;

>}

Вытеснение и переключение контекста

Переключение контекста — это переключение от одной, готовой к выполнению задачи к другой. Это переключение производится с помощью функции >context_switch()