Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Добавление в очередь ожидания
Для добавления спящего процесса в очередь ожидания используется две функции: 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; 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)
{ 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 демонстрирует основные используемые для этого функции.
Рис. 3.15. График вызова wait_event*0 Мы отследим и опишем интерфейсы, связанные с wait_event (), и опишем ее от Очередь ожидания 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 Инициализация описателя очереди ожидания для текущего процесса и добавление Строки 127-132 Этот код устанавливает бесконечный цикл, который будет прерван только по наступлении ожидаемого события. Перед блокировкой по наступлению события мы установим состояние процесса в TASK_INTERRUPTIBLE с помощью макроса Глава 3 • Процессы: принципиальная модель выполнения set__current_s tate. Вспомним, что этот макрос связан с указателем на текущий имеет значительное отличие; он устанавливает поле состояния процесса в 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 () с разны 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)); Очередь ожидания 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; 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, указатель на очередь ожида Глава 3 • Процессы: принципиальная модель выполнения Строки 2340, 2342 Эти строки устанавливают и снимают кольцевую блокировку очереди ожидания. Строка 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; 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; Просмотров: 1022; Нарушение авторского права страницы