Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Добавление в очередь ожидания



Для добавления спящего процесса в очередь ожидания используется две функции: add_wait_queue () и add_wait_queue_exclusive (). Для обеспечения двух ви­дов сна процесса существует две функции. Неэксклюзивный ожидающий процесс - это процесс, который ожидает наступления состояния, не разделяемого с другими ожи­дающими процессами. Эксклюзивный ожидающий процесс ожидает наступления состоя­ния, которое ожидает другой процесс, что потенциально может привести к соревнованию между процессами.

Функция add_wait__queue () вставляет неэксклюзивный процесс в очередь ожи­дания. Неэксклюзивный процесс в любом случае будет разбужен ядром, как только насту­пит событие, которого он ожидает. Функция устанавливает поле flags структуры очере­ди ожидания в соответствующее спящему процессу значение 0, устанавливает блокировку очереди ожидания для избежания прерывания при доступе к той же очереди и возникно­вения соревновательной ситуации, добавляет структуру в список очереди ожидания и за­тем снимает с очереди ожидания блокировку, делая ее доступной для других процессов.

kernel/fork.с

93 void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)

94 {

95 unsigned long flags;
96

97 wait-> flags & = ~WQ_FLAG_EXCLUSIVE;

98 spin_lock_irqsave(& q-> lock, flags); 9 9 add_wai t_queue(q, wait);

 

100 spin_unlock_irqrestore(& q-> lock, flags);

101 }

Функция add_wait_queue_exclusive() вставляет эксклюзивный процесс в очередь ожидания. Функция устанавливает поле flags структуры очереди ожидания в 1 и далее работает аналогично add_wait_queue О, за исключением того, что экс­клюзивный процесс добавляется в конец очереди. Это означает, что в конкретной очереди ожидания неэксклюзивные процессы находятся в начале, а эксклюзивные - в конце. Это необходимо, как мы увидим далее при рассмотрении пробуждения процессов, для того, чтобы процессы в очереди ожидания будились именно в такой последовательности.



Глава 3 • Процессы: принципиальная модель выполнения


kernel/fork.с

105 void add__wait_queue_exclusive(wait_queue_head_t *q,

wait_queue_t * wait)

106 107 108 109 110 111 112 113

{

unsigned long flags;

wait-> flags |= WQ_FLAG_EXCLUSIVE; spin_lock_irqsave(& q-> lock, flags);

_ add_wait_queue_tail(q, wait);

spin__unlock_irqrestore(& q-> lock, flags)

}


3.7.2 Ожидание события

Интерфейсы sleep_on (), sleep_on__timeout () и interruptible_sleep__on (), еще поддерживаемые в 2.6, в версии 2.7 будут удалены. Поэтому мы рассмотрим только интерфейс wait_event* (), пришедший на смену интерфейсу sleep_on* ().

Интерфейс wait_event* () включает в себя wait_event О, wait_event_ interruptible () и wait__event_interruptible_timeout (). Рис. 3.15 демон­стрирует основные используемые для этого функции.

 

         
wait_event()   wait_event_interruptible()   wait_eventjnterruptible_timeout()
> '            
_wait_event()   _wait_event_interruptible()   _wait_event_interruptible_timeout()
                 
  scheduleQ   schedule_timeout()  
               
                       

Рис. 3.15. График вызова wait_event*0

Мы отследим и опишем интерфейсы, связанные с wait_event (), и опишем ее от­
личия от других двух функций. Интерфейс wait__event () является оберткой вокруг вы­
зова__ wai t_event () с бесконечным циклом, который прерывается, только если насту­
пает ожидаемое событие; wait_event_interruptible__timeout () передает тре­
тий параметр вызова ret типа int, используемый для передачи времени ожидания.


Очередь ожидания



wait_event_interruptible () является единственным из трех интерфейсов, который возвращает значение, которое равно -ERESTARTSYS, если сигнал прерывает ожидаемое событие, или 0, если событие насупило:

include/linux/wait.h

137 #define wait_event(wq, condition)

138 do {

139 if (condition)

140 break;

141 __ wait_event(wq, condition);

142 } while (0)

Интерфейс___ wait_event () выполняет всю работу по изменению состояния

процесса и манипуляции с описателем:

include/linux/wait.h

121 #define _ wait_event(wq, condition)

122 do {

 

123 wait__queue_t wait;

124 init_waitqueue_entry(& _ wait, current);

126 add_wai t_queue (& wq, & ____ wait);

127 for (;; ) {

 

128 set_current_state(TASK_UNINTERRUPTIBLE);

129 if (condition) 13 0 break;

131 scheduleO;

132 }

133 current-> state = TASK_RUNNING;

134 remove_wai t_queue (& wq, & _ wai t);

135 } while (0)

Строки 124-126

Инициализация описателя очереди ожидания для текущего процесса и добавление
описателя в передаваемую очередь ожидания. До этого момента wait_event_
interruptible и wait_event_interruptible_timeout выглядят иден­
тично __ wait_event.

Строки 127-132

Этот код устанавливает бесконечный цикл, который будет прерван только по насту­плении ожидаемого события. Перед блокировкой по наступлению события мы уста­новим состояние процесса в TASK_INTERRUPTIBLE с помощью макроса



Глава 3 • Процессы: принципиальная модель выполнения


set__current_s tate. Вспомним, что этот макрос связан с указателем на текущий
процесс, поэтому нам не нужно передавать в него информацию о процессе.
Как только он заблокирован, он передает процессор следующему процессу с помо­
щью вызова scheduler (). В этом смысле______ wait_event_interruptible ()

имеет значительное отличие; он устанавливает поле состояния процесса в TASK_UNINTERRUPTIBLE и ожидает вызова для текущего процесса signal_

pending; __wait_event_interruptible_timeout очень похож на_____________ wait_

event_interruptible за исключением вызова schedule_timeout () вместо schedule () при вызове планировщика; schedule_timeout получает в качест­ве параметра длительность времени ожидания, который передается в оригинальный интерфейс wait__event_interruptible_timeout.

Строки 133-134

В этом участке кода наступает ожидаемое событие, или для двух других интерфей­сов может быть получен сигнал, или будет исчерпано время ожидания. Поле state описателя процесса устанавливается в TASK_RUNNING (планировщик помещает процесс в очередь выполнения). Наконец, запись удаляется из очереди ожидания. Функция remove_wait__queue () блокирует очередь ожидания перед удалением записи и снимает блокировку перед выходом.

Пробуждение

Процесс будет разбужен, как только наступит ожидаемое им событие. Обратите внима­ние, что процесс может заснуть самостоятельно, но не может самостоятельно проснуться. Для пробуждения задач, находящихся в очереди ожидания, может использоваться мно­жество макросов, но все они применяют три основные функции пробуждения. Макросы

wake__up, wake_up_nr, wake_up_all/ wake_up_interraptible, wake_up_ interruptible_nr и wake_up_interraptible_all вызывают функцию

__ wake_up() с разными параметрами. Макросы wake_up_all_sync и

wake_up_interruptible_sync вызывают функцию__________ wake_up_sync () с разны­
ми параметрами. И наконец, макрос wake_up_locked по умолчанию вызывает функ­
цию __ wake_up_locked ():

include/linux/wait.h

116 extern void FASTCALL(_ wake_up(wait_queue_head_t *q,

unsigned int mode, int nr) );

117 extern void FASTCALM__ wake_up_locked(wait_queue_head_t *q,

unsigned int mode));

118 extern void FASTCALM__ wake_up_svnc (wait_queue_head_t *q,

unsigned int mode, int nr));
119
120 #define wake_up(x) _ wake_up( (x), TASK_UNINTERRUPTIBLE |


Очередь ожидания



TASK_INTERRUPTIBLE, l)

121 #define wake_up_nr(х, nr) _ wake_up( (x), TASK_UNINTERRUPTIBLE |

TASK_INTERRUPTIBLE, nr)

122 #define wake_up_all(x) _ wake_up( (x), TASK_UNINTERRUPTIBLE |

TASK_INTERRUPTIBLE, 0)

123 #define wake_up_all_sync (x) ____ wake_up_sync ( (x), TASK_UNINTERRUPTIBLE

| TASK__INTERRUPTIBLE, 0)

124 #define wake_up_interruptible(x) _ wake_up((x),

TASK_INTERRUPTIBLE, 1)

125 #define wake_up_interruptible_nr (x, nr)

_ wake_up( (x), TASK_INTERRUPTIBLE, nr)

126 #define wake_up_interruptible_all(x)

_ wake_up((x), TASK_INTERRUPTIBLE, 0)

127 #define wake_up_locked(x) _ wake_up_locked((x),

TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)

128 #define wake_up_interruptible__sync (x) _____ wake_up_sync ( (x),

TASK_INTERRUPTIBLE, 1

129 )

Давайте посмотрим на__ wake___up ():

kernel/sched.с

2336 void fastcall ________ wake_up(wait_queue_Jiead_t *q,

unsigned int mode, int nr_exclusive)

2337 {

2338 unsigned long flags;
2339

2340 spin_lock_irqsave(& q-> lock, flags);

2341 ___ wake_up_common(q, mode, nr__exclusive, 0);

2342 spin_unlock_irqrestore(& q-> lock, flags);

2343 }

Строка 2336

Параметры, передаваемые в _ wake_up, включают q, указатель на очередь ожида­
ния; mode, индикатор типа пробуждаемого потока (определяется состоянием пото­
ка); и nr_exclusive, который указывает эксклюзивное и неэксклюзивное пробу­
ждение. Эксклюзивное пробуждение (когда nr_exclusive=0) пробуждает все за­
дачи в очереди (как эксклюзивные, так и неэксклюзивные), тогда как
неэксклюзивное пробуждение пробуждает все неэксклюзивные задачи и только
одну эксклюзивную задачу.



Глава 3 • Процессы: принципиальная модель выполнения


Строки 2340, 2342

Эти строки устанавливают и снимают кольцевую блокировку очереди ожидания.
Блокировка устанавливается перед вызовом ____ wake_up_common () для ис­
ключения возможности возникновения соревнования.

Строка 2341

Функция__ wake_up_common () выполняет основные операции функции wakeup:

kernel/sched.с

2313 static void _ wake_up_.common(wait_.queue_head_t *q,

unsigned int mode, int nr_exclusive, int sync)

2314 {

2315 struct list_head *tmp, *next;
2316

2317 list_for__each_safe(tmp, next, & q-> task_list) {

2318 wait_queue_t *curr;

2319 unsigned flags;

2320 curr = list_entry(tmp, wait_queue_t, task_list);

2321 flags = curr-> flags;

2322 if (curr-> func(curr, mode, sync) & &

 

2323 (flags & WQ_FLAG_EXCLUSIVE) & &

2324! —nr_exclusive)

2325 break;

2326 }

2327 }

Строка 2313

Параметры, передаваемые в__ wake__up_common (), - это q, указатель на очередь

ожидания; mode, тип пробуждаемого потока; nr_exclusive, тип предыдущего пробуждения, и sync, который указывает, должно ли пробуждение быть синхрони­зированным.

Строка 2315

Здесь мы устанавливаем временные указатели для работы с элементами списка.

Строка 2317

Макрос list_for_each_safe сканирует каждый элемент очереди ожидания. Это начало нашего цикла.

Строка 2320

Макрос list__enrty возвращает адрес структуры очереди ожидания, хранимый в переменной tmp.


Поделиться:



Популярное:

Последнее изменение этой страницы: 2016-03-25; Просмотров: 952; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.049 с.)
Главная | Случайная страница | Обратная связь