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



>struct runqueue {

> spinlock_t lock; /* спин-блокировка для зашиты этой очереди выполнения */

> unsigned long nr_running; /* количество задач, готовых к выполнению */

> unsigned long nr_switches; /* количество переключений контекста */

> unsigned long expired timestamp; /* время последнего обмена массивами */

> unsigned long nr_uninterruptible; /* количество заданий в состоянии

>                                      непрерываемого ожидания */

> unsigned long long timestamp last tick; /* последняя метка времени

>                                            планировщика */

> struct task_struct *curr; /* текущее задание, выполняемое на данном

>                              процессоре */

> struct task_struct *idle; /* холостая задача данного процессора */

> struct mm_struct *prev_mm; /* поле mm_struct последнего выполняемого

>                               задания */

> struct prio_array *active; /* указатель на активный массив приоритетов */

> struct prio_array *expired; /* указатель на истекший

>                                массив приоритетов */

> struct prio_array arrays[2]; /* массивы приоритетов */

> struct task_struct *migration_thread; /* миграционный поток для

>                                          данного процессора */

> struct list_head migration_queue; /* миграционная очередь для

>                                      данного процессора */

> atomic_t nr_iowait; /* количество заданий, ожидающих на ввод-вывод */

>};

Поскольку очередь выполнения — это основная структура данных планировщика, существует группа макросов, которые используются для доступа к определенным очередям выполнения. Макрос >cpu_rq(processor) возвращает указатель на очередь выполнения, связанную с процессором, имеющим заданный номер. Аналогично макрос >this_rq() возвращает указатель на очередь, связанную с текущим процессором. И наконец, макрос >task_rq(task) возвращает указатель на очередь, в которой находится соответствующее задание.

Перед тем как производить манипуляции с очередью выполнения, ее необходимо заблокировать (блокировки подробно рассматриваются в главе 8, "Введение в синхронизацию выполнения кода ядра"). Так как очередь выполнения уникальна для каждого процессора, процессору редко необходимо блокировать очередь выполнения другого процессора (однако, как будет показано далее, такое все же иногда случается). Блокировка очереди выполнения позволяет запретить внесение любых изменений в структуру данных очереди, пока процессор, удерживающий блокировку, выполняет операции чтения или записи полей этой структуры. Наиболее часто встречается ситуация, когда необходимо заблокировать очередь выполнения, в которой выполняется текущее задание. В этом случае используются функции