O Torvalds Linus

Сайт о *nix системах и всем что с ними связано

Новую голову очереди ожидания можно создать с помощью макроса

DECLARE_WAIT_QUEUE_HEAD (паше), КОТОрЫЙ СТаТИЧеСКИ объявляет НОВуЮ Переменную с именем паше в качестве головы очереди ожидания и инициализирует ее ПОЛЯ lock И task list. Функция init waitqueue head () может быть ИСпользована для инициализации головы очереди ожидания, для которой переменная была выделена динамически.

ФуНКЦИЯ init waitqueue entry (q,p) инициализирует Структуру q ТИПа wait queue t Следующим образом:

q ->flags = 0; q ->task = р;

q ->func = default_wake_function;

He эксклюзивный процесс p будет разбужен функцией defauit_wake_ function о, которая является интерфейсной функцией для try_to_wake_up().

Альтернативный макрос definewait объявляет новую переменную wait queue t и инициализирует ее дескриптором текущего процесса и адресом функции autoremove_wake_function(), ИСПОЛЬЗуемОЙ ДЛЯ пробуждения. Эта функция вызывает функцию default_wake_function(), чтобы разбудить спящий процесс, а затем удаляет соответствующий элемент из списка очереди на ожидание.

Функция add wait queue () ставит не эксклюзивный процесс на первое место в списке очереди ожидания. Функция add wait queue exciusive о ставит эксклюзивный процесс на последнее место в списке. Функция remove_ wait queueo удаляет процесс из списка очереди ожидания, а функция waitqueue active о проверяет, пуст ли заданный список очереди ожидания.

Процесс, собирающийся подождать наступления некоторого события, может вызвать одну из следующих функций:

? функция sieep on о работает с текущим процессом:

void sleep_on(wait_queue_head_t wq)

(

wait_queue_t wait;

init_waitqueue_entry(&wait, current); current ->state = TASK UNINTERRUPTIBLE;

add_wait_queue(wq, &wait); / wq указывает на голову очереди ожидания /

schedule();

remove_wait_queue(wq, &wait);

)

Функция переводит текущий процесс в состояние taskjjninterruptible и заносит его в указанную очередь ожидания. Затем она вызывает планировщик, который возобновляет выполнение другого процесса. Когда спящий процесс будет разбужен, планировщик возобновит выполнение функции sieep on (), которая удалит процесс из очереди ожидания;

? функция interruptible sleep on () идентична функции sleep_on(), за исключением того, что она переводит процесс в состояние task_ interrupt ible, а не task_uninterrupt ible, чтобы процесс можно было разбудить и с помощью сигнала;

? функции sleep_on_timeout () И interruptible_sleep_on_timeout () аналогичны предыдущим, но они также позволяют вызвавшему процессу определить временной интервал, по истечении которого ядро должно разбудить процесс. С этой целью они вызывают функцию schedule timeout о, а не schedule о? функции prepare_to_wait (), prepare_to_wait_exclusive () И finish_wait (), впервые появившиеся в Linux 2.6, предлагают еще один способ перевода процесса в состояние сна и занесения его в очередь ожидания.

Функции prepare_to_wait () И prepare_to_wait_exclusive () переводят процесс в состояние, определяемое третьим параметром, а затем устанавливают флаг эксклюзивности в элементе очереди ожидания в значение 0 (не эксклюзивный) или 1 (эксклюзивный) соответственно. Наконец, они заносят элемент wait очереди ожидания в список, определяемый головой очереди wq.

Сразу после своего пробуждения процесс вызывает функцию finish_ wait (), которая переводит его обратно в состояние task running (на тот

случай, если условие пробуждения будет выполнено до вызова функции schedule ()), и удаляет соответствующий элемент из списка очереди на выполнение (если это еще не было сделано функцией, разбудившей процесс);

? макросы wait event И wait event interruptible переводят вызвавший процесс в состояние сна и заносят его в очередь ожидания, пока указанное условие не будет удовлетворено. Например, макрос wait event (wq, condition) развертывается в следующий фрагмент.

Сделаем несколько замечаний по поводу перечисленных функций. Функции, аналогичные sieep ono, не могут быть использованы в типичной ситуации, когда необходимо проверить условие и атомарным образом перевести процесс в состояние сна, если условие не удовлетворено. По этой причине, учитывая, что они хорошо известны как источник конфликтных ситуаций, их применение не рекомендуется.

Кроме того, чтобы поставить эксклюзивный процесс в очередь ожидания, ядро должно вызвать функцию prepare_to_wait_exciusive о (или непосредственно функцию add wait queue exciusiveо). Наконец, если не используется НИ DEFINE WAIT, НИ f inish wait (), ядро должно удалить элемент из списка очереди ожидания после пробуждения процесса.

Ядро будит процессы в очередях ожидания, переводя их в состояние? все макросы работают со спящими процессами, находящимися в состоянии taskinterruptible. Если имя макроса не содержит строку “interruptible”, он работает также и с процессами в task uninterruptible;

все макросы будят все не эксклюзивные процессы, находящиеся в требуемом состоянии;

макросы, имена которых содержат строку “nr”, будят заданное количество эксклюзивных процессов, находящихся в требуемом состоянии (это количество передается в качестве параметра макроса). Макросы, имена которых содержат строку “all”, будят все эксклюзивные процессы, находящиеся в требуемом состоянии. Наконец, макросы, имена которых не содержат ни “nr”, ни “all”, будят только один эксклюзивный процесс, находящийся в требуемом состоянии;

? макросы, имена которых не содержат строку “sync”, сравнивают приоритеты разбуженных процессов с приоритетами процессов, выполняемых в системе в этот момент, и вызывают функцию schedule о, если необходимо. Макросы, имена которых содержат строку “sync”, такую проверку не делают, и, следовательно, выполнение разбуженного процесса с высоким приоритетом может быть немного задержано;

? макрос wake up iocked аналогичен макросу wake up с тем отличием, что он вызывается, когда спин – блокировка в структуре wait queue head t уже захвачена.

Например, макрос wake up фактически эквивалентен следующему фрагменту кода.

Макрос list for each перебирает все элементы двунаправленного списка q ->task_iist, т. е. все процессы в очереди ожидания. Для каждого элемента макроса list entry вычисляет адрес соответствующей переменной wait queue t. Поле func этой переменной содержит адрес пробуждающей функции, которая пытается разбудить процесс, идентифицируемый полем task элемента очереди ожидания. Если процесс действительно был разбужен (функция возвратила 1), и он является эксклюзивным (поле curr ->fiags содержит 1), цикл заканчивается.

Add A Comment