Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

На главную -> MyLDP -> Электронные книги по ОС Linux
Цилюрик О.И. Модули ядра Linux
Назад Вперед

Беглый взгляд на программирование модуля

Все мы умеем и имеем больший или меньший опыт написания программ в Linux 1, которые все, между тем, имеют абсолютно идентичную единую структуру:

	int main( int argc, char *argv[] ) { 
	   // и здесь далее следует любой программный код, вплоть до вот такого: 
	   printf( "Hello, world!\n" ); 
	   // ... и далее, далее, далее ...
	   exit( EXIT_SUCCESS );
	};

Такую структуру в коде будут неизменно иметь все приложения-программы, будь то тривиальная показанная «Hello, world!», или «навороченная» среда разработки Eclipse 2. Это — в подавляющем большинстве встречаемый случай: пользовательское приложение начинающееся с main() и завершающееся по exit().

Ещё один встречающийся (но гораздо реже) в UNIX случай — это демоны: программы, стартующие с main(), но никогда не завершающие своей работы (чаще всего это сервера различных служб). В этом случае для того, чтобы стать сервером, всё тот же пользовательский процесс должен выполнить некоторую фиксированную последовательность действий [20], называемую демонизацией, который состоит в том, чтобы (опуская некоторые детали для упрощения):

  • создать свой собственный клон вызовом fork() и завершить родительский процесс;
  • создать новую сессию вызовом setsid(), при этом процесс становится лидером сессии и открепляется (теряет связь) от управляющего терминала;
  • позакрывать все ненужные файловые дескрипторы (унаследованные).

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

Возникает вопрос: а может ли пользователь написать и выполнить собственный код, выполняющийся в режиме супервизора, а, значит, имеющий полномочия расширять (или даже изменять) функциональность ядра Linux? Да, может! И эта техника программирования называется программированием модулей ядра. И именно она позволяет, в частности, создавать драйверы нестандартного оборудования 3.

Примечание: Как мы будем неоднократно видеть далее, установка (запуск) модуля выполняется посредством специальных команд установки, например, командой:

# insmod <имя-файла-модуля>.ko

После чего в модуле начинает выполняться функция инициализации. Возникает вопрос: а можно ли (при необходимости) создать пользовательское приложение, стартующее, как обычно, с точки main(), а далее присваивающее себе требуемые привилегии, и выполняющееся в супервизорном режиме (в пространстве ядра)? Да, можно! Для этого изучите исходный код утилиты insmod (а Linux — система с абсолютно открытым кодом всех компонент и подсистем), а утилита эта является ничем более, как заурядным пользовательским приложением, выполните в своём коде те манипуляции с привилегиями, которые проделывает insmod, и вы получите желаемое приложение. Естественно, что всё это потребует от приложения привилегий root при запуске, но это то же минимальное требование, которое обязательно при работе с модулями ядра.


1) Замечание здесь о Linux не является оговоркой, а означает, что вышесказанное верно только для операционных систем, языком программирования для которых (самих систем) является классический язык C; в этом контексте точнее говорить даже не о системе Linux, а о любых UNIX-like или POSIX системах.

2) В качестве примера Eclipse указан также не случайно: а). это один из инструментов, который может эффективно использоваться в разработках модулей, и особенно если речь зайдёт о клоне Android на базе ядра Linux, и б). даже несмотря на то, что сам Eclipse писан на Java, а вовсе не на С - всё равно структура приложения сохранится, так как с вызова main() будет начинаться выполнение интерпретатора JVM, который далее будет выполнять Java байт-код. То же относится и к приложениям, написанным на таких интерпретирующих языках как Perl, Python, или даже на языке командного интерпретатора shell: точно ту же структуру приложения будет воспроизводить само интерпретирующее приложение, которое будет загружаться прежде интерпретируемого кода.

3) Это (написание драйверов) - самое важное, но не единственное предназначение модулей в Linux: «всякий драйвер является модулем, но не всякий модуль является драйвером».


Предыдущий раздел: Оглавление Следующий раздел:
Источники информации   Наш первый модуль ядра