Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ядро Linux.doc
Скачиваний:
3
Добавлен:
01.03.2025
Размер:
117.25 Кб
Скачать

Каналы.

Канал— это коммуникационное устройство, допускающее однонаправленное взаимодействие. Данные, записываемые на "входном" конце канала, читаются на "выходном" его конце. Каналы являются последовательными устройствами: данные всегда читаются в том порядке, в котором они были записаны. Канал обычно используется как средство связи между двумя потоками одного процесса или между родительским и дочерним процессами.

В интерпретаторе команд канал создается оператором |. Например, показанная ниже команда заставляет интерпретатор запустить два дочерних процесса, один — для программы ls, а второй — для программы less:

# Is | less

Интерпретатор также формирует канал, соединяющий стандартный выходной поток подпроцесса ls со стандартным входным потоком подпроцесса less. Таким образом, имена файлов, перечисляемые программой ls, посылаются программе постраничной разбивки less в том порядке, в котором они отображались бы на терминале.

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

Рассмотрим пример взаимодействия двух процессов с помощью канала.

#include <iostream>

int main(){

char * message = (char *) malloc (sizeof(char) * 10);

std::cin >> message;

std::cout << "Message: "<< message << std::endl;

free (message);

return 0;}

Теперь, если скомпилировать программу и запустить echo "pipe" | <program>, где program – имя готовой программы, то на экран выводится сообщение "Message: pipe"

echo "pipe" |

Linux kernel API

Интерфейс программирования приложений (англ. Application Programming Interface, API;) — набор методов (функций), который программист может использовать для доступа к функциональности программной компоненты (программы, модуля, библиотеки). API является важной абстракцией, описывающей функциональность "в чистом виде".

API определяет функциональность, которую предоставляет программа (модуль, библиотека), при этом API позволяет абстрагироваться от того, как именно эта функциональность реализована.

Если программу (модуль, библиотеку) рассматривать как чёрный ящик, то API — это множество "ручек", которые доступны пользователю данного ящика, которые он может вертеть и дёргать.

Linux kernel API или API ядра linux – это API, предоставляющий однообразный метод модулям устройств и другому низкоуровневому ПО получать доступ к системным ресурсам и службам.

Простейший модуль

В качестве примера linux kernel API приведем исходный текст самого простого модуля ядра, какой только возможен.

Пример hello.c:

#include <linux/module.h> // Необходим для любого модуля ядра #include <linux/kernel.h> // Здесь находится определение KERN_ALERT int init_module(void) { printk("<1>Hello world 1.\n"); /* Если вернуть ненулевое значение, то это будет воспринято как признак ошибки, возникшей в процессе работы init_module; в результате модуль не будет загружен. */ return 0;} void cleanup_module(void) { printk(KERN_ALERT "Goodbye world 1.\n");}

Любой модуль ядра должен иметь по меньшей мере хотя бы две функции: функцию инициализации модуля -- init_module(), которая вызывается во время загрузки модуля, и функцию завершения работы модуля -- cleanup_module(). Начиная с ядра, версии 2.3.13, требования к именованию начальной и конечной функций были сняты. Теперь вы можете давать им свои имена. Новый метод именования является более предпочтительным, однако многие по-прежнему продолжают использовать имена init_module() и cleanup_module().

Обычно функция init_module() выполняет регистрацию обработчика какого-либо события или замещает какую-либо функцию в ядре своим кодом (который, как правило, выполнив некие специфические действия, вызывает оригинальную версию функции в ядре). Функция cleanup_module() является полной противоположностью, она производит "откат" изменений, сделаных функцией init_module(), что делает выгрузку модуля безопасной.

И наконец, любой модуль ядра должен подключать заголовочный файл linux/module.h. В нашем примере мы подключали еще один файл -- linux/kernel.h, но лишь для того, чтобы получить доступ к определению KERN_ALERT

Несмотря на столь красноречивое название, функция printk() вовсе не предназначена для вывода информации на экран, даже не смотря на то, что мы использовали ее в своем примере именно для этой цели! Основное назначение этой функции -- дать ядру механизм регистрации событий и предупреждений. Поэтому, каждый вызов printk() сопровождается указанием приоритета, в нашем примере это <1> и KERN_ALERT. Всего в ядре определено 8 различных уровней приоритета для функции printk() и каждый из них имеет свое макроопределение, таким образом нет необходимости писать числа, лишенные смысла (имена уровней приоритета и их числовые значения вы найдете в файле linux/kernel.h). Если уровень приоритета не указывается, то по-умолчанию он принимается равным DEFAULT_MESSAGE_LOGLEVEL.

Если задан уровень ниже, чем int console_loglevel, то сообщение выводится на экран. Если запущены и syslog, и klogd, то сообщение попадет также и в системный журнал /var/log/messages, при этом оно может быть выведено на экран, а может и не выводиться. Мы использовали достаточно высокий уровень приоритета KERN_ALERT для того, чтобы гарантировать вывод сообщения на экран функцией printk().