Читаем Разработка ядра Linux полностью

Единственный параметр функции — это желаемое относительное время, выраженное в количестве импульсов системного таймера. В этом примере задание переводится в прерываемое состояние ожидания, которое будет длиться s секунд. Поскольку задание отмечено как TASK_INTERRUPTIBLE, то оно может быть возвращено к выполнению раньше времени, как только оно получит сигнал. Если не нужно, чтобы код обрабатывал сигналы, то можно использовать состояние TASK_UNINTERRUPTIBLE. Перед вызовом функции schedule_timeout() задание должно быть в одном из этих двух состояний, иначе задание в состояние ожидания переведено не будет.

Следует обратить внимание, что поскольку функция schedule_timeout() использует планировщик, то код, который ее вызывает, должен быть совместим с состоянием ожидания. Обсуждение, посвященное атомарности и переходу в состояние ожидания, приведено в главах 8 и 9. Если коротко, то эту функцию необходимо вызывать в контексте процесса и не удерживать при этом блокировку.

Функция schedule_timeout() достаточно проста. Она просто использует таймеры ядра. Рассмотрим эту функцию подробнее.

signed long schedule_timeout(signed long timeout) {

 timer_t timer;

 unsigned long expire;

 switch (timeout) {

 case MAX_SCHEDULE_TIMEOUT:

  schedule();

  goto out;

 default:

  if (timeout < 0) {

   printk(KERN_ERR "schedule_timeout: wrong timeout "

    "value %lx from %p\n", timeout, builtin_return_address(0));

   current->state = TASK_RUNNING;

   goto out;

  }

 }

 expire = timeout + jiffies;

 init_timer(&timer);

 timer.expires = expire;

 timer.data = (unsigned long) current;

 timer.function = process_timeout;

 add_timer(&timer);

 schedule();

 del_timer_sync(&timer);

 timeout = expire - jiffies;

out:

 return timeout < 0 ? 0 : timeout;

}

Эта функция создает таймер timer и устанавливает время срабатывания в значение timeout импульсов системного таймера в будущем. В качестве обработчика таймера устанавливается функция process_timeout(), которая вызывается, когда истекает период времени таймера. Далее таймер активизируется, и вызывается функция schedule(). Так как предполагается, что текущее задание находится в состоянии TASK_INTERRUPTIBLE или TASK_UNINTERRUPTIBLE, то планировщик не будет выполнять текущее задание, а выберет для выполнения другой процесс.

Когда интервал времени таймера истекает, то вызывается функция process_timeout(), которая имеет следующий вид.

void process_timeout(unsigned long data) {

 wake_up_process((task_t*)data);

}

Эта функция устанавливает задание в состояние TASK_RUNNING и помещает его в очередь выполнения.

Когда задание снова планируется на выполнение, то оно возвращается в функцию schedule_timeout() (сразу после вызова функции schedule()). Если задание возвращается к выполнению преждевременно, то таймер ликвидируется. После этого задание возвращается из функции ожидания по тайм-ауту.

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

Ожидание в очереди wait queue в течение интервала времени

В главе 4 рассматривалось, как контекст процесса в ядре может поместить себя в очередь ожидания для того, чтобы ждать наступления некоторого события, а затем вызвать планировщик, который выберет новое задание для выполнения. Если где-то в другом месте произойдет указанное событие, то вызывается функция wake_up() для всех заданий, которые ожидают в очереди. Эти задания возвращаются к выполнению и могут продолжать работу.

Перейти на страницу:

Похожие книги

C++: базовый курс
C++: базовый курс

В этой книге описаны все основные средства языка С++ - от элементарных понятий до супервозможностей. После рассмотрения основ программирования на C++ (переменных, операторов, инструкций управления, функций, классов и объектов) читатель освоит такие более сложные средства языка, как механизм обработки исключительных ситуаций (исключений), шаблоны, пространства имен, динамическая идентификация типов, стандартная библиотека шаблонов (STL), а также познакомится с расширенным набором ключевых слов, используемым в .NET-программировании. Автор справочника - общепризнанный авторитет в области программирования на языках C и C++, Java и C# - включил в текст своей книги и советы программистам, которые позволят повысить эффективность их работы. Книга рассчитана на широкий круг читателей, желающих изучить язык программирования С++.

Герберт Шилдт

Программирование, программы, базы данных