Лекция 10. Linux-specific

Сегодня вместо Георгия Владимироваича Евгений Леонидович.

Тема сегодняшней лекции программирование в линукс.

Linux-specific.

Или за что вас будут не любить те, кто будет портировать ваш код на другие ос.

Линукс помимо того, что предоставляет апи позикса, предоставляет ряд средств для делания вещей более лучше или вообще иначе. Основным программным интерфейсом взаимодействия пользовательских программ и линукса является линукс апи, предоставляемое в виде системных вызовов.

Помимо декларированных в позикс есть ряд линукс-специфичных.

Итак, первое линукс-специфик

API

Значительно пересекается с POSIX. В попытке реализовать POSIX-совместимое API становится понятно, что в реальной жизни всё не так хорошо. Есть ряд вещей, которых нет в POSIX’е, но хорошо бы иметь. Что сюда входит

POSIX&Linux extensions

Говорим про них вместе, так как достаточно сложно разделять, для много верны обе классификации.

Начнем с модели управления процесса и управления памятью. Это довольно важно.

Управление процессами

СЕЛинукс? Раньше для него приходилось хачить ядро, теперь есть ядерные интерфейся для добавления секьюрити модуля, который добавляет секьюрити проверки соответственно собственному разумению, эти модули могут быть разными. Апарм, СЕЛинукс.

В чем идея с тредами. Для тредов есть local storage, чтобы у каждого было свое личное адресное пространство -- это может быть реализовано как компилятроом, так и на уровне ядра. влинуксе есть на уровне ядра. У вас есть дополнительные системные вызовы. gettid(), get/set_thread_area(), ну и, соответственно, tkill(). Чтобы эта реализация была более менее прозрачной, у вас есть главный тред и тред_ид главного треда совпдаает с процесс_ид. Если вы не думаете о тредах, у вас все прозрачно, иначе надо использовать дополнительные вызовы. Ими же пользуется библиотека pthreads. Есть ли смысл пользоваться напрямую ядерными вызовами? tkill вы не сможете сделать напрямую. Есть ряд системных вызовов которыми надо указывать тред_ид, а без системного вызова его не получить. птредс вещь внутри себя, внешней штукой ими управлять не получится. птредс они про другое, про многопоточное програмиирование, а системных вызовов полторы штуки. В птредс большинство вызовов именно тред_авар, а не для работы с собственно тредами. Ещё сисвызовы для тредов tgkill(), exit_group(). Как создать тред? clone(). Или clone2(). Есть такая мода давать цифровые суффиксы всяким модным вызовам. epoll_create epoll_create1 вызовы более крутые в том плане, что у них поменялся ап/би??, то есть не апби ааа.

Как работает шедулер в линуксе? Линукс не парится. Когда аффинити не задан, то он будет раскидывать страницы как попало, и процесс будет работать на процессоре каком попало, потому что доступ к странице своей/нее своей все равно достаточно дорогие по сравнению с кешами. От перекидывания на другой процессор получается больше ущерба чем от неправильной аффинити. Но мемори менеджер это штука такая. Перебалансировка по нодам делается чуть ли не раз в полсекунды.

Есть возможность привязать процесс не к ядру? Сетаффинити. А сет_мем полиси позволяет указать мемори пулл, который надо использовать данному процессу.

капабилити это ряд прав/возможнстей, позволяющих выполнять различные системные вещи -- монтирование, сет_уид, итд. Капабилитей много. как рут так и не рут могут вполне себе ими обладать или не обладать. С одной стороны можете получить возможность сделать рута распредленным. Такое было впервые реализовано в солярис. Из соляриса перетащили много секьюити фишек - пам, капабилити, в каком-то плане контейнеры и процесс аккаунтинг. тем не менее сейчас влинуксе это все есть, капабилити появились достаточно давно,Ю кажется в 2.2. Управлять темикакпабилити которые вам доступны можно через prctl(). Там можно получить и задать маску доступных, можно задать маску капабилитей которые дети не получат, и так далее. когда вы планируете делать клон вы можете уаказать что наследует дочерний процесс в том числе и касательно капабилетей. Кстати, посредством клон сейчас реализуется форк, потому что он более круче. capget(), capset() позволяют указывать непосрдественные капабилити тредов. Да.

proc namespaces. Иногда хочется изолировать процессы от окружающего мира тем или иным образом. Изолировать хочется по разному, например дать и мдругой рут, например не показывать им другие процессы, не показыавть им какую-нибудь информацию о системе касающуюся памяти и процессора и так далее. Неймспейсы позволяют это делать. Вы можете породить новый неймспейс у процесса и сказать, что там новая жизнь. Он будет не в курсее про другие процессы и не сможет общаться с другими процессами даже посрдеством сигналов, хоть и будет от того же пользователя. вызов seths(). Gjxtve pfujdjhbkb ghj fengjqyn? gjnjve xnj [jntkb egjvzynm ghj зшмще_кщще и у какого то вызова , маунта или нет, есть возможность указывать какие маунты видит процесс и все его дети. Кажется это делается prctl().

Есть ещё такая смешная штука, которая позволяет менять поведение ядра для дерева процессов. Это нужно в основном для всякой портабилити ятобы всяике процессы написанные для других юниксов могли работать в линуксе. Такие специального вида костыли. getrusage()

Работа с файлами

Там гораздо больше всякого интересного. Файловый интерфейс этоосновной способ абстракции любого ввода-вывода. Как следствие этот интерфейс функуионально довольно богат и там наиболее интересные механизмы которые интересны и с тз юзерспейса. С расширениями касающимися работы с файлами вы столкнетесь почти наверняка.

Есть ещё одна задача, которая касается слежения за всякими событими в системе. Было два механизма dnotify и inotify. dnotify делался через fctrl вы могли взять дескриптор соотв директории и могли передать дескриптор директории для ..

На смену dnotify примерно во времена ядра 2.5. пришел inotify. В маске вы указываете много клёвых параметров, за которыми вы хотите наблюдать.

infd = inotify_init() wd = inotify_add_watch(infd, path, mask)

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

Делается просто рид и читаете вы оттуда структуру соответствующего вида. структура Notify_event в которой указан вотч_дескриптор, указано чего случилось посредством аналогичной маски.

Когда говорили про управление памятью там еще один аспект возможно стоит подчеркнуть. Маппинги довольно смещно осуществлялись одно время. В связи с необходимостью 64 битных оффсетов. Помимо мап в ядре сейчас определён мап2, которые принимает смещение по страницам. Единственная архитектруа которая в 32 битном режиме может адресов более чем 32-битные адреса это х86 PAE, но в люом случае есть мап64 у которой 2 параметра типа старший бит и младший бит.

По поводу памяти ещё есть возможность ремапить всякие вещи. map из позикса, а вот remap нет и без него страдали.

Ещё можно делать нелинейный мапинг.

sys_info позволяет много чего получить.

Большинство из этого неактально для юзерспейс программистов.

Во Фре есть kqueue который очень крутой и умеет тоже самое что epoll, inotify и не только.

Юзерспейс программисты обычно просто берут и используют libevent.

А вот то, что касается файловых систем эт оштука более приближенная к юзерспейсу в том плане, что пользоваться ей можно из любой программы. Специальные фс доступны посредством стандартного файлового интерфейса.

Файловые системы специалных функций довольного много. Самые известные procfs. Впервые она появилась в солярисе или бзд, она позволяла и позволяет узнавать информацию о процессах. Линукс отличается тем что прокфс есть кроме информации о процессах много чего. Интерфейс прокфс довольно простой. Многие ядерные подсистемы экспрортируют туда информацию о себе и позволяют собой управлять. Когда создается там файл создается структура с коллбэками на чтение и на запись.

/proc/sys

/proc/sys/ возможность воздействия на ядро — лимиты, особенности поведения. То же самое делается посредством сисвызова sysctl(). Сисктл доступно довольно много чего. net, kernel, vm, fs. Помимо этого в самом прокфсе ещё... вот.

Гораздо интересней другая специальная фс.

sysfs. Это способ просмотра иерархии kobject это часть объектной модели ядра Линукс. Нельзя пафосно сказать, что она там есть, но там можно создавать объекты и предоставлять к ним доступ на чтение и запись и механизм событий. Из юзерспейса возможны колбэки на чтение запись в sysfs. Когда вы в sysfs добавляете файл, вы добьавляете объект в определённую подсистему, а там уже предоставляются аттрибуты для доступа к объектам. Сам кобжект это директория а аттрибуты это уже регулярные файлы.

Может кто-то не в курсе, как организуются подобные штуки в ядре.

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

struct my_obj{

struct kobjext kobj;}

container_of(obj, struct my_obj, kobj)

Далее после того как вы создали структуру вы можете делать kobject_init для инициализации этого поля внутри структуры. После вы можете делать kobject_add и на этом этапе вы должны указать ktyoe которая должна быть проассоцирована с этим объектом. Это надо затем что а, да. Структуру ктайп вы указывате ещё на этапе инициализации. Когда вы добавляете вы указываете родителя данного объекта. У кобжекта есть имя. Оно тоже определяется посредством API. . Это рассказывается чтобы вы сбее представляли как устроен сисфс.

Как устроен рефкаунтинг? Когда вы хотите поработать с кобжектом, вы сначала делеает kobject_get, потом kobject_put. Если рефкаунтер дропнулся до нуля, т ообъект удаляется. рефкаунтеры инкрементятся на каждый адд у парента, но если вы сделали циклическую зависимость, то вы перед кобжект релиз должны сделать кобжект дел.

Чтоюбы получать доступ к аттрибутам сисфс есть вызовы sysfs_create_file и sysfs_create_group — первое позволяет создавать кобжекты. второе каталоги их группирующие. Сисфс гораздо более внятно организована сама по себе когнитивных свойств не несет, а просто предоставляет доступ к иерархии кобжектов, но на ней надложено дополнительное полиси как должны себе вести какие модули. Модули ядра которые работают с пси, итд соблюдают неокторые правила и генерируют все красиво. Туда перетащили доступ к платформе, к ацпи. Все мигрирует из прока в сисфс, потому что уже ненужно например уеликом реализовать семантику чтения и доступа к файлам итп. Там еще подсистема наворчивает свои коллбэки.

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

у селинукс есть своя фс, которой он управляется и у cgroups тоже.

Костыли-костыли. Если кто не знает read ahead, который позволяет сказать закэшируй кусок файла я его сейчас прочитаю это тоже тркщтр

Поскольку с Линуксом ассоциировано некоторое окружение, то пользуясь расширениями этого окружения вы впадаете в линукс специфик.

glibc,gnu lib c , мантейнтится в районе редхата.Это двольно развесистая и тяжелая библиотека со своими особенностями. Там появились библиотечные вызовы с суффикосм с для некоторых вещей у которых не было нормального о. Помните наверное фгетс у которого не было нормальной обработки баффероверфлоу, таких вызово намного больше, которым хорошо было бы передавать количество байт.

coreutils также имеют расширений вагон и маленькую тележку потому что то, что специфицировано в POSIX, совсем грустно. Берёте, открываете любой мануал по coreutils и находите у команд по две трети GNU-специфичных опций. xargs

В Линуксе поддерживают расгиренные аттрибуты и есть специальное апи по их управлению. они умеют указывать что файл имеет соотв капабилити.

shell(bash). некоторые сичтают что програмиирование на баше это программирование на шелле. Это не так. Баш не стандартизован, набор возможностей меняется с каждой версией. и даже если говрите #!/bin/bash вы моложец что не сказали бин ш, но непонятно какой это бэш первый,второй, третий.

Башизмы

Ещё в баше есть довольно удобная штука — как узнать, внутри какого файла вы находитесь, в случае сорсинга. В баше есть специальный массив exec path, в котором в нулевом элементе путь до текущего исп скрипта в следующих вся ... вызовов.

Далеко не всё, чем богат Линукс, здесь рассказано. xattr, и ещё много, что лектор вспомнил, но забыл. Среди костылей есть много костылей, без которых жить очень грустно.

LecturesCMC/LinuxApplicationDevelopment2012/Conspects/10 (последним исправлял пользователь Nyarcel 2013-01-25 07:50:15)