Linux Device Drivers 3 / Драйверы устройств Линукс (третье издание): 5.4. Completions
| Английский оригинал | Перевод на русский | |
|---|---|---|
Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
5.4. Завершения hardorsoft 06.12.10 в 04:12 |
|
|
struct semaphore sem; hardorsoft 06.12.10 в 04:13 |
||
|
Внешняя задача может затем по завершении своей работы вызвать up(&sem). hardorsoft 06.12.10 в 04:14 |
||
|
Как оказалось, семафоры не лучший инструмент для использования в этой ситуации. При нормальном использовании код, пытающийся блокировать семафор, находит, что семафор доступен почти всё время; если есть значительные соперничество за семафор, страдает производительность и схема блокировки должна быть пересмотрена. Так что семафоры были сильно оптимизированы для "подходящих" случаев. Однако, при использовании для общения при завершении задачи показанным выше способом поток, вызывающий down, почти всегда вынужден ждать; соответственно, пострадает производительность. При использовании этого способа семафоры могут также стать предметом (неприятного) состояния гонок, если они объявлены как автоматические переменные. В некоторых случаях семафор мог бы исчезнуть до того, как процесс, вызывающий up, закончит с ним работу. hardorsoft 06.12.10 в 04:14 |
||
|
Эти опасения побудили добавить в ядре версии 2.4.7 интерфейс "завершения" (completions). Ожидание завершения является легковесным механизмом с одной задачей: позволить одному потока рассказать другому, что работа выполнена. Чтобы воспользоваться механизмом завершения, ваш код должен подключить <linux></linux>completion.h>. "Завершение" может быть создано с помощью: hardorsoft 06.12.10 в 04:16 |
||
|
DECLARE_COMPLETION(my_completion); hardorsoft 06.12.10 в 04:16 |
||
|
Или, если "завершение" должно быть создано и проинициализировано динамически: hardorsoft 06.12.10 в 04:16 |
||
|
struct completion my_completion; hardorsoft 06.12.10 в 04:17 |
||
|
Ожидание "завершения" является простым делом вызова: hardorsoft 06.12.10 в 04:17 |
||
|
void wait_for_completion(struct completion *c); hardorsoft 06.12.10 в 04:18 |
||
|
Обратите внимание, что эта функция выполняет непрерываемое ожидание. Если ваш код вызовет wait_for_completion и никто никогда не завершит задачу, результатом будет неубиваемый процесс.(* На момент написания, патчи, добавляющие прерываемые версии, были в обращении, но не были объединены с главной веткой.) hardorsoft 06.12.10 в 04:18 |
||
|
С другой стороны, о фактическом завершении события можно просигнализировать одним из следующих вызовов: hardorsoft 06.12.10 в 04:18 |
||
|
void complete(struct completion *c); hardorsoft 06.12.10 в 04:18 |
||
|
Эти две функции ведут себя иначе, если более, чем один поток ожидает того же сообщения завершения. complete будит только один из ожидающих потоков, а complete_all позволяет продолжиться всем. В большинстве случаев есть только один ожидающий и две функции будут давать идентичные результаты. hardorsoft 06.12.10 в 04:20 |
||
|
"Завершение", как правило, одноразовое устройство; оно используется однажды, а затем отбрасывается. Однако, вполне возможно повторное использование структур "завершения", если об этом правильно позаботиться. Если complete_all не используется, структура "завершения" может быть использована снова без каких-либо проблем, пока нет никакой двусмысленности в том, о каком событии в настоящее время просигнализировано. Но если вы используете complete_all, вы должны переинициализировать структуру "завершения" перед повторным использованием. Этот макрос: hardorsoft 06.12.10 в 04:20 |
||
|
INIT_COMPLETION(struct completion c); hardorsoft 06.12.10 в 04:20 |
||
|
может быть использован для быстрого выполнения такой повторной инициализации. hardorsoft 06.12.10 в 04:20 |
||
|
В качестве примера того, как может быть использовано "завершение", рассмотрим модуль complete, который включён в исходник примера. Этот модуль определяет устройство с простой семантикой: любой процесс, пытающийся прочитать из устройства будет ждать (используя wait_for_completion), пока в устройство пишет какой-нибудь другой процесс. Код, который реализует это поведение: hardorsoft 06.12.10 в 04:21 |
||
|
(* На момент написания, патчи, добавляющие прерываемые версии, были в обращении, но не были объединены с главной веткой.) hardorsoft 06.12.10 в 04:21 |
||
|
DECLARE_COMPLETION(comp); hardorsoft 06.12.10 в 04:21 |
||
|
Можно иметь несколько процессов "читающих" из этого устройства в одно и то же время. Каждая запись в устройство вызовет по завершении только одну операцию чтения, но нет способа узнать, какую именно. hardorsoft 06.12.10 в 04:21 |
||
|
Типичным использованием механизма завершения является прекращение потока ядра во время завершения работы модуля. В случае прототипа, какое-то действие внутри драйвера выполняется потоком ядра в цикле while (1). Когда модуль готов к очистке, функция выхода сообщает потоку, что завершается, а затем ожидает завершения. С этой целью, ядро включает в себя специфическую функцию, которая будет использоваться потоком: hardorsoft 06.12.10 в 04:22 |
||
|
void complete_and_exit(struct completion *c, long retval); hardorsoft 06.12.10 в 04:22 |
