Linux откуда запускается программа

Я начал изучать программы драйверов для Linux, но мне это немного сложно.

Я изучал драйвер i2c и довольно запутался относительно точки входа в программу драйвера. Программа драйвера запускается с макроса MOUDULE_INIT() ?

И я также хотел бы знать, как я могу узнать, как работает программа драйвера. У меня есть книга «Драйвер устройства Linux», но я все еще в полном замешательстве. Не могли бы вы помочь мне? Большое спасибо.

В качестве примера возьму драйвер i2c. В нем столько функций, я просто хочу знать, как я могу получить координирующую связь функций в драйверах i2c?

Alexander 16 Окт 2012 в 18:37

6 ответов

Лучший ответ

«Linux Device Driver» — хорошая книга, но она старая!

#include #include #include MODULE_LICENSE(«GPL»); MODULE_AUTHOR(«Name and e-mail»); MODULE_DESCRIPTION(«my_first_driver»); static int __init insert_mod(void) < printk(KERN_INFO «Module constructor»); return 0; >static void __exit remove_mod(void) < printk(KERN_INFO «Module destructor»); >module_init(insert_mod); module_exit(remove_mod);

Современное руководство, действительно хорошо написанное, называется «Linux Серия драйверов устройств «

Запуск Windows программ в Linux | Какой из 3-х вариантов окажется лучше? HGL, Bottles, PortProton

Rob 29 Дек 2020 в 16:47
23 Мар 2013 в 11:07

Я думаю, ОП был доволен краткостью и ссылкой; не очень беспокоило отсутствие конкретных ответов на его вопросы.

TheCodeArtist
15 Апр 2014 в 13:23
Ссылка не работает.
AJMansfield
26 Апр 2019 в 17:36

Возможно, это поможет перестать думать о драйвере устройства как о программе. Они совсем другие. Программа имеет определенную начальную точку, выполняет некоторые действия и имеет одну или несколько достаточно хорошо определенных (ну, в любом случае, они должны) точки выхода. У драйверов есть кое-что, что нужно сделать при первой загрузке (например, MODULE_INIT() и другие вещи), и они могут или не могут когда-либо делать что-либо снова (вы можете принудительно загрузить драйвер для оборудования, которого на самом деле нет в вашей системе) , и может потребоваться кое-что сделать, если драйвер когда-либо будет выгружен. Помимо этого, драйвер обычно предоставляет некоторые определенные точки входа (системные вызовы, ioctls и т. Д.), К которым пользовательские приложения могут получить доступ, чтобы запросить у драйвера какие-либо действия.

Ужасная аналогия, но подумайте о программе как о машине: вы садитесь, заводите ее, едете куда-то и выходите. Драйвер больше похож на торговый автомат: вы подключаете его и проверяете, что он заполнен, но потом люди просто время от времени приходят и нажимают кнопки, чтобы заставить его что-то сделать.

twalberg 16 Окт 2012 в 18:58

На самом деле вы сначала беретесь за драйвер платформы (I2C) (Native), вам нужно понять, как вызывается MOUDULE_INIT () драйвера платформы по сравнению с другими загружаемыми модулями.

brasofilo 2 Июн 2014 в 11:04

Начало модуля ядра начинается с функции инициализации, к которой в основном обращаются с помощью макроса __init перед именем функции.

Сложно ли переходить на Linux?

Макрос __init указывает ядру Linux, что следующая функция является функцией инициализации, и ресурс, который будет использоваться для этой функции инициализации, будет свободен после выполнения кода функции инициализации.

Существуют и другие маркеры, используемые для обнаружения функции инициализации и выпуска, с именами module_init () и module_exit () [как описано выше].

Эти два макроса используются, если драйвер устройства настроен на работу как загружаемый и удаляемый модуль ядра во время выполнения [т.е. с помощью команды insmod или rmmod]

meAbab 29 Фев 2016 в 14:56

Вкратце и чётко: он начинается с .probe и доходит до init, как только вы выполняете insmod. Это также регистрирует драйвер в подсистеме драйверов и также запускает init. Каждый раз, когда функции драйвера вызываются из пользовательского приложения, функции вызываются с помощью обратного вызова.

Raulp 10 Авг 2016 в 09:49

Драйвер устройства — это не «программа», у которой есть main <> с начальной и конечной точкой. Это больше похоже на API, библиотеку или набор процедур. В данном случае это набор точек входа , объявленных MODULE_INIT() , MODULE_EXIT() , возможно EXPORT_SYMBOL() , и структур, которые перечисляют точки входа для операций .

Для блочных устройств ожидается, что драйвер предоставит список операций, которые он может выполнять, объявив свои функции для этих операций в (из include/linux/blkdev.h ):

Читайте также:
Характеристика программ в Microsoft

struct block_device_operations < int (*open) (); int (*release) (); int (*ioctl) (); int (*compat_ioctl) (); int (*direct_access) (); unsigned int (*check_events) (); /* ->media_changed() is DEPRECATED, use ->check_events() instead */ int (*media_changed) (); void (*unlock_native_capacity) (); int (*revalidate_disk) (); int (*getgeo)(); /* this callback is with swap_lock and sometimes page table lock held */ void (*swap_slot_free_notify) (); struct module *owner; >;

Для символьных устройств ожидается, что драйвер предоставит список операций, которые он может выполнять, объявив свои функции для этих операций в (из include/linux/fs.h ):

struct file_operations < struct module *owner; loff_t (*llseek) (); ssize_t (*read) (); ssize_t (*write) (); ssize_t (*aio_read) (); ssize_t (*aio_write) (); int (*readdir) (); unsigned int (*poll) (); long (*unlocked_ioctl) (); long (*compat_ioctl) (); int (*mmap) (); int (*open) (); int (*flush) (); int (*release) (); int (*fsync) (); int (*aio_fsync) (); int (*fasync) (); int (*lock) (); ssize_t (*sendpage) (); unsigned long (*get_unmapped_area)(); int (*check_flags)(); int (*flock) (); ssize_t (*splice_write)(); ssize_t (*splice_read)(); int (*setlease)(); long (*fallocate)(); >;

Для платформенных устройств ожидается, что драйвер предоставит список операций, которые он может выполнять, объявив свои функции для этих операций в (из include/linux/platform_device.h ):

struct platform_driver < int (*probe)(); int (*remove)(); void (*shutdown)(); int (*suspend)(); int (*resume)(); struct device_driver driver; const struct platform_device_id *id_table; >;

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

Программа драйвера запускается с макроса MOUDLUE_INIT ()?

Подпрограмма драйвера init () , указанная в MODULE_INIT() , будет вызываться во время загрузки (когда она статически связана) или когда модуль загружается динамически. Драйвер передает свою структуру операций подсистеме устройства, когда он регистрирует себя во время своей init () .

Эти точки входа драйвера устройства, например open () или read () обычно выполняются, когда пользовательское приложение вызывает вызов библиотеки C (в пространстве пользователя) и после переключения в пространство ядра. Обратите внимание, что рассматриваемый вами драйвер i2c является драйвером платформы для шины, которая используется листовыми устройствами, и ее функции, предоставляемые EXPORT_SYMBOL() , будут вызываться другими драйверами.

Гарантированно вызывается только процедура драйвера init () , указанная в MODULE_INIT() . Подпрограмма драйвера exit () , указанная в MODULE_EXIT() , будет выполняться только в том случае, если / когда модуль динамически выгружается. Операционные процедуры драйвера будут вызываться асинхронно (как и его подпрограмма обслуживания прерывания) в неизвестном порядке. Надеемся, что пользовательские программы вызовут open () перед выполнением операции read () или ioctl () и вызовут другие операции в разумном мода. Хорошо написанный и надежный драйвер должен учитывать любой порядок или последовательность операций и давать разумные результаты для обеспечения целостности системы.

Источник: question-it.com

Как определить, откуда приложение запущено?

Когда я набираю имя некоторого исполняемого файла в командной строке, и он запускается, как я могу определить путь, где расположен этот исполняемый файл?

задан user626528 342

2 ответа 2

Вы можете узнать, какой исполняемый файл будет запущен с помощью команды

which

Если вы хотите определить путь программным путем, вы используете неверный обмен стека.

ответ дан Uwe Plonus 1k

Проблема простого решения

which command находит исполняемый файл данной command в вашем $PATH . К сожалению, это не будет работать, как ожидалось, во всех случаях.

Когда command является псевдонимом или функцией, вы не получите правильный результат, потому что фактический исполняемый файл может иметь совершенно другое имя. Например, во многих дистрибутивах Linux псевдоним ll установлен по умолчанию. which ll не найдет ничего. Другой проблемный случай, когда ваша оболочка ведет себя нестандартным образом и не запускает первую command найденную в $PATH .

Более надежное решение

В Linux, если вы хотите быть полностью уверены в пути к исполняемому файлу запущенного процесса, вы можете получить его из его PID (ID процесса; в приведенном ниже примере вместо $PID ):

readlink /proc/$PID/exe

Как получить номер? PID последнего запуска процесса в оболочке в фоновом режиме — $! , Небольшая демонстрация:

sleep 20 https://poweruser.guru/questions/614921/%D0%BA%D0%B0%D0%BA-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C-%D0%BE%D1%82%D0%BA%D1%83%D0%B4%D0%B0-%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B7%D0%B0%D0%BF%D1%83%D1%89%D0%B5%D0%BD%D0%BE» target=»_blank»]poweruser.guru[/mask_link]

Доступ процессов к файлам и каталогам

Аннотация: В лекции описываются понятия процесса в Linux, алгоритм порождения новых процессов и одно из средств межпроцессного взаимодействия – сигналы. Рассматриваются три вида доступа к ресурсам файловой системы – чтение, запись и использование, их различия для файлов и каталогов, а также команды изменения доступа.

Читайте также:
Как увеличить громкость микрофона с помощью программ на ПК

Процессы

Как уже упоминалось в лекции 1, загрузка Linux завершается тем, что на всех виртуальных консолях (на самом деле – на всех терминалах системы), предназначенных для работы пользователей, запускается программа getty . Программа выводит приглашение и ожидает активности пользователя, который может захотеть работать именно на этом терминале. Введенное входное имя getty передает программе login , которая вводит пароль и определяет, разрешено ли работать в системе с этим входным именем и этим паролем. Если login приходит к выводу, что работать можно, она запускает стартовый командный интерпретатор , посредством которого пользователь и управляет системой.

Выполняющаяся программа называется в Linux процессом . Все процессы система регистрирует в таблице процессов , присваивая каждому уникальный номер – идентификатор процесса ( p rocess id entificator, PID ). Манипулируя процессами , система имеет дело именно с их идентификаторами , другого способа отличить один процесс от другого, по большому счету, нет. Для просмотра своих процессов можно воспользоваться утилитой ps (» p rocess s tatus»):

5.1. Просмотр таблицы собственных процессов

Здесь Мефодий вызвал ps с ключом » -f » (» f ull»), чтобы добыть побольше информации. Представлены оба принадлежащих ему процесса : стартовый командный интерпретатор , bash , и выполняющийся ps . Оба процесса запущены с терминала tty3 (третьей системной консоли ) и имеют идентификаторы 3590 и 3624 соответственно. В поле PPID (» p arent p rocess id entificator») указан идентификатор родительского процесса , т. е. процесса , породившего данный. Для ps это – bash , а для bash , очевидно, login , так как именно он запускает стартовый shell . В выдаче не оказалось строки для этого login , равно как и для большинства других процессов системы, так как они не принадлежат пользователю methody .

Процесс — выполняющаяся программа в Linux. Каждый процесс имеет уникальный идентификатор процесса , PID. Процессы получают доступ к ресурсам системы (оперативной памяти, файлам, внешним устройствам и т. п.) и могут изменять их содержимое. Доступ регулируется с помощью идентификатора пользователя и идентификатора группы , которые система присваивает каждому процессу .

Запуск дочерних процессов

Запуск одного процесса вместо другого организован в Linux с помощью системного вызова exec() . Старый процесс из памяти удаляется навсегда, вместо него загружается новый, при этом настройка окружения не меняется, даже PID остается прежним. Вернуться к выполнению старого процесса невозможно, разве что запустить его снова с помощью того же exec() (от «execute» – «исполнить»). Кстати, имя файла (программы), из которого запускается процесс , и собственное имя процесса (в таблице процессов ) могут и не совпадать. Собственное имя процесса – это такой же параметр командной строки, как и те, что передаются ему пользователем: для exec() требуется и путь к файлу, и полная командная строка, нулевой (стартовый) элемент которой – как раз название команды 1 Нулевой параметр — argv[0] в терминах языка Си и $0 в терминах shell. .

Вот откуда » — » в начале имени стартового командного интерпретатора ( -bash ): его «подсунула» программа login , чтобы была возможность отличать его от других запущенных тем же пользователем оболочек.

Для работы командного интерпретатора одного exec() недостаточно. В самом деле, shell не просто запускает утилиту, а дожидается ее завершения, обрабатывает результаты ее работы и продолжает диалог с пользователем. Для этого в Linux служит системный вызов fork() («вилка, развилка»), применение которого приводит к возникновению еще одного, дочернего , процесса – точной копии породившего его родительского . Дочерний процесс ничем не отличается от родительского : имеет такое же окружение, те же стандартный ввод и стандартный вывод , одинаковое содержимое памяти и продолжает работу с той же самой точки (возврат из fork() ). Отличий два: во-первых, эти процессы имеют разные PID, под которыми они зарегистрированы в таблице процессов , а во-вторых, различается возвращаемое значение fork() : родительский процесс получает в качестве результата fork() идентификатор процесса-потомка , а процесс-потомок получает » 0 «.

Дальнейшие действия shell при запуске какой-либо программы очевидны. Shell-потомок немедленно вызывает эту программу с помощью exec() , а shell-родитель дожидается завершения работы процесса-потомка ( PID которого ему известен) с помощью еще одного системного вызова , wait() . Дождавшись и проанализировав результат команды, shell продолжает работу:

Читайте также:
Найдите ошибки в записи программы program умножение var

5.2. Создание бесконечно выполняющегося сценария

По совету Гуревича Мефодий создал сценарий для sh (или bash , на таком уровне их команды совпадают), который ничего не делает. Точнее было бы сказать, что этот сценарий делает ничего, бесконечно повторяя в цикле команду , вся работа которой состоит в том, что она завершается без ошибок (в лекции 7 говорится о том, что » > файл » в командной строке просто перенаправляет стандартный вывод команды в файл). Запустив этот сценарий с помощью команды вида sh имя_сценария , Мефодий ничего не увидел, но услышал, как загудел вентилятор охлаждения центрального процессора: машина трудилась! Управляющий символ » ^C «, как обычно, привел к завершению активного процесса , и командный интерпретатор продолжил работу.

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

5.3. Запуск фонового процесса

В результате стартовый командный интерпретатор ( PID 3590) оказался родителем сразу двух процессов : sh , выполняющего сценарий loop , и ps .

Процесс , запускаемый параллельно, называется фоновым (background). Фоновые процессы не имеют возможности вводить данные с того же терминала, что и породивший их shell (только из файла), зато выводить данные на этот терминал могут (правда, когда на одном и том же терминале вперемешку появляются сообщения от нескольких фоновых процессов , начинается неразбериха). При каждом терминале в каждый момент времени может быть не больше одного активного (foreground) процесса , которому разрешено вводить данные с этого терминала. На время, пока команда (например, cat ) работает в активном режиме, породивший ее командный интерпретатор «уходит в фон», и там, в фоне, выполняет свой wait() .

активный процесс , foreground process — процесс , предоставляющий возможность вводить данные с терминала..

Фоновый процесс , background process — процесс , не имеющий возможности вводить данные с терминала. Пользователь может запустить любое, но не превосходящее заранее заданное в системе, число фоновых процессов .

Стоит заметить, что параллельность работы процессов в Linux – дискретная. Здесь и сейчас выполняться может столько процессов , сколько центральных процессоров есть в компьютере (например, один).

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

В выдаче ps , которую получил Мефодий, можно заметить, что PID стартовой оболочки равен 3590 , а PID запущенных из-под него команд (одной фоновой и одной активной) – 3634 и 3635 . Это значит, что за время, прошедшее с момента входа Мефодия в систему до момента запуска sh loop S «, S leep, поля STAT , status): ждет завершения активного процесса , top .

Увидев такое разнообразие информации, Мефодий кинулся читать руководство по top , однако скоро понял, что без знания архитектуры Linux большая его часть не имеет смысла. Впрочем, некоторая часть все же понятна: объем оперативной памяти (всей, используемой и свободной), время работы машины, объем памяти, занимаемой процессами и т. п.

Последний процесс , запущенный из оболочки в фоне, можно из этой оболочки сделать активным при помощи команды fg (» f ore g round» – «передний план»):

5.5. Перевод фонового процесса в активное состояние с помощью команды fg (foreground)

Услужливый bash даже написал командную строку, которой был запущен этот процесс : » bash loop «. Мефодий решил «убить» его с помощью управляющего символа » ^C «. Теперь последним запущенным в фоне процессом стал sh , выполняющий сценарий loop .

Источник: intuit.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru