Роберт Лав - Разработка ядра Linux
- Название:Разработка ядра Linux
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс
- Год:2006
- Город:Москва
- ISBN:5-8459-1085-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Роберт Лав - Разработка ядра Linux краткое содержание
В книге детально рассмотрены основные подсистемы и функции ядер Linux серии 2.6, включая особенности построения, реализации и соответствующие программны интерфейсы. Рассмотренные вопросы включают: планирование выполнения процессов, управление временем и таймеры ядра, интерфейс системных вызовов, особенности адресации и управления памятью, страничный кэш, подсистему VFS, механизмы синхронизации, проблемы переносимости и особенности отладки. Автор книги является разработчиком основных подсистем ядра Linux. Ядро рассматривается как с теоретической, так и с прикладной точек зрения, что может привлечь читателей различными интересами и потребностями.
Книга может быть рекомендована как начинающим, так и опытным разработчикам программного обеспечения, а также в качестве дополнительных учебных материалов.
Разработка ядра Linux - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
struct my_struct mine = {
.list = LIST_HEAD_INIT(mine.list),
.dog = 0,
.cat = NULL
};
Для того чтобы создать и инициализировать связанный список, можно использовать следующее объявление.
static LIST_HEAD(fox);
Эта команда позволяет статически создать связанный список с именем fox
.
Нет необходимости явно выполнять какие-либо операции со служебными полями элементов связанного списка. Вместо этого необходимо просто включить структуру узла связанного списка в вашу структуру данных, чтобы можно было легко манипулировать данными и выполнять прохождение по связанному списку.
Работа со связанными списками
Для работы со связанными списками ядро предоставляет семейство функций. Все они принимают указатели на одну или более структур list_head
. Все функции выполнены как функции с подстановкой тела (inline) на языке С, и их все можно найти в файле .
Интересно, что время выполнения всех этих функций масштабируется как O(1) [97] Вопросы сложности алгоритмов рассматриваются в приложении В.
. Это значит, что они выполняются в течение постоянного интервала времени независимо от количества элементов списка, для которого они вызываются. Например, время добавления элемента в связанный список из 3 и 3000 элементов будет одинаковым. Это, возможно, и не вызывает удивления, но тем не менее, приятно.
Для добавления элемента в связанный список можно использовать следующую функцию.
list_add(struct list_head *new, struct list head *head);
Эта функция добавляет узел new
в заданный связанный список сразу после элемента head
. Поскольку связанный список является кольцевым и для него не существует понятий первого и последнего узлов, в качестве параметра head
можно использовать указатель на любой элемент списка. Если в качестве рассмотренного параметра всегда передавать указатель на последний элемент, то эту функцию можно использовать для организации стека.
Для добавления элемента в конец связанного списка служит следующая функция.
list_add_tail(struct list_head *new,
struct list_head *head);
Эта функция добавляет новый элемент new в связанный список сразу перед элементом, на который указывает параметр head
. Поскольку связанный список является кольцевым, то, как и в случае функции list_add()
, в качестве параметра head
можно передавать указатель на любой элемент списка. Эту функцию можно использовать для реализации очереди, если передавать указатель на первый элемент.
Для удаления узла списка служит следующая функция.
list_del(struct list_head *entry);
Эта функция позволяет удалить из списка элемент, на который указывает параметр entry
. Обратите внимание, что эта функция не освобождает память, выделенную под структуру данных, содержащую узел списка, на который указывает параметр entry
. Данная функция просто удаляет узел из списка. После вызова этой функции обычно необходимо удалить структуру данных, в которой находится узел list_head
.
Для удаления узла из списка и повторной инициализации этого узла служит следующая функция.
list_del_init(struct list head *entry);
Эта. функция аналогична функции list_del()
, за исключением того, что она дополнительно инициализирует указанную структуру list_head
из тех соображений, что эта структура данных больше не нужна в качестве элемента текущего списка и ее повторно можно использовать.
Для перемещения узла из одного списка в другой предназначена следующая функция.
list_move(struct list_head *list, struct list_head *head);
Эта функция удаляет элемент list
из одного связанного списка и добавляет его в другой связанный список после элемента head
.
Для перемещения элемента из одного связанного списка в конец другого служит следующая функция.
list_move_tail(struct list_head *list,
struct list_head *head);
Эта функция выполняет то же самое, что и функция list_move()
, но вставляет элемент перед элементом head
.
Для проверки того, пуст ли список, служит функция.
list_empty(struct list_head *head);
Эта функция возвращает ненулевое значение, если связанный список пуст, и нулевое значение в противном случае.
Для объединения двух не перекрывающихся связанных списков служит следующая функция.
list_splice(struct list_head *list,
struct list_head *head);
Эта функция вставляет список, на который указывает параметр list
, в другой список после параметра head.
Для объединения двух не перекрывающихся списков и повторной инициализации старого головного элемента служит следующая функция.
list splice_init(struct list head *list, struct list head *head);
Эта функция аналогична функции list_splice()
, за исключением того, что параметр list
, представляющий список, из которого удаляются элементы, повторно инициализируется.
Если вам уже доступны указатели next
и prev
, то можно сэкономить пару процессорных тактов (в частности, время выполнения операций разыменования указателей) путем вызова внутренних функций работы со связанными списками. Все ранее рассмотренные функции в сущности не делают ничего, кроме получения указателей next
и prev
и вызовов внутренних функций. Внутренние функции имеют те же имена, что и их оболочки, но перед именем используется два символа подчеркивания. Вместо того чтобы вызвать функцию list_del(list)
, можно вызвать функцию __list_del(prev, next)
. Это имеет смысл, только когда указанные указатели уже известны. В противном случае просто получится некрасивый код. Для подробной информации об этих интерфейсах можно обратиться к файлу .
Перемещение по связанным спискам
Теперь мы уже знаем, как объявлять, инициализировать и работать со связанными списками в ядре. Это все хорошо, но не имеет никакого смысла, если нет возможности работать С данными, которые хранятся в списках! Связанный список — это просто контейнер, в котором хранятся важные данные. Необходимо иметь способ перемещения по списку и доступа к данным. К счастью, ядро предоставляет набор полезных интерфейсов для перемещения по связанным спискам и обращения к структурам данных, которые хранятся в этих списках.
Обратите внимание, что, в отличие от подпрограмм управления списками, операции перебора элементов списка из n
узлов масштабируются как O(n) .
Наиболее простой способ выполнять итерации по элементам связанного списка — это использовать макрос list_for_each()
. Этот макрос принимает два параметра — указатели на структуры list_head
. Первый параметр указывает на текущий элемент списка, а второй — на любой элемент списка, для которого необходимо обойти все узлы. На каждой итерации цикла первый параметр макроса указывает на текущий элемент списка, пока не будут пройдены все элементы, как в следующем примере.
Интервал:
Закладка: