Главная страница
Навигация по странице:

  • Файловые системы и пространства имен

  • Иерархия процессов

  • Пользователи и группы

  • Права доступа

  • Системное программирование Линукс. Linux. Системное программирование. Вступление


    Скачать 0.65 Mb.
    НазваниеLinux. Системное программирование. Вступление
    АнкорСистемное программирование Линукс
    Дата23.01.2023
    Размер0.65 Mb.
    Формат файлаpdf
    Имя файлаLinuxSystemProgramming.pdf
    ТипКраткое содержание
    #900372
    страница6 из 14
    1   2   3   4   5   6   7   8   9   ...   14
    43
    Напротив, доступ к блочному устройству происходит как к массиву байтов.
    Драйвер устройства отображает массив байтов на устройство с возможностью позиционирования, и пользовательское пространство может в произвольном по­
    рядке обращаться к любым валидным байтам массива, то есть можно сначала прочитать байт 12, потом байт 7, потом опять байт 12. Блочные устройства — это обычно устройства для хранения информации. Жесткие диски, дисководы гибких дисков, CD­ROM, флэш­накопители — все это примеры блочных устройств. До­
    ступ к ним осуществляется через файлы блочных устройств.
    Именованные каналы (часто обозначаемые аббревиатурой FIFO — «первым при­
    шел, первым обслужен») — это механизм межпроцессного взаимодействия (IPC), предоставляющего канал связи для дескриптора файла. Доступ к именованному каналу выполняется через специальный файл. Обычные конвейеры применяются именно для того, чтобы «перекачивать» вывод одной программы во ввод другой; они создаются в памяти посредством системного вызова и не существуют в какой­либо файловой системе. Именованные каналы действуют как и обычные, но обращение к ним происходит через файл, называемый специальным файлом FIFO. Несвязанные процессы могут обращаться к этому файлу и обмениваться информацией.
    Последний тип специальных файлов — это сокеты. Сокеты обеспечивают усо­
    вершенствованную разновидность межпроцессного взаимодействия между двумя несвязанными процессами — не только на одной машине, но и даже на двух разных.
    На самом деле сокеты являются основополагающей концепцией всего программи­
    рования для сетей и Интернета. Существует множество разновидностей сокетов, в том числе доменные сокеты UNIX. Последние используются для взаимодействия на локальной машине. В то время как сокеты, обменивающиеся информацией по
    Интернету, могут использовать пару из хост­имени и порта для идентификации
    «цели» взаимодействия, доменные сокеты используют для этого специальный файл, расположенный в файловой системе. Часто его называют просто сокет­файлом.
    Файловые системы и пространства имен
    Linux, как и все системы UNIX, предоставляет глобальное и единое пространство
    имен для файлов и каталогов. В некоторых операционных системах отдельные физические и логические диски разделяются на самостоятельные пространства имен. Например, для доступа к файлу на дискете может использоваться путь
    A:\
    plank.jpg
    , а пути ко всем файлам на жестком диске будут начинаться с
    C:\
    . В UNIX тот же файл с дискеты может быть доступен через
    /media/floppy/plank.jpg или даже через
    /home/captain/stuff/plank.jpg
    , в одном ряду с файлами с других носителей.
    В этом и выражается единство пространства имен в UNIX.
    Файловая система — это набор файлов и каталогов формальной и валидной иерархии. Файловые системы можно по отдельности добавлять к глобальному пространству имен и удалять их из этого глобального пространства файлов и каталогов. Данные операции называются монтированием и размонтировани-
    ем. Каждая файловая система может быть индивидуально монтирована к кон­
    кретной точке пространства имен. Она обычно называется точкой монтирова-
    ния. В дальнейшем из точки монтирования открывается доступ к корневому
    Концепции программирования в Linux

    44
    каталогу файловой системы. Например, CD может быть монтирован в точке
    /me- dia/cdrom
    , в результате чего корневой каталог файловой системы компакт­дис­
    ка также будет доступен через
    /media/cdrom
    . Файловая система, которая была монтирована первой, находится в корне пространства имен,
    /
    , и называется
    корневой файловой системой. Во всех системах Linux всегда имеется корневая файловая система. Монтирование других файловых систем в тех или иных точках в Linux не является обязательным.
    Файловые системы обычно существуют физически (то есть сохраняются на диске), хотя в Linux также поддерживаются виртуальные файловые системы, су­
    ществующие лишь в памяти, и сетевые файловые системы, существующие одно­
    временно на нескольких машинах, работающих в сети. Физические файловые системы находятся на блочных устройствах хранения данных, в частности на компакт­дисках, дискетах, картах флэш­памяти, жестких дисках. Некоторые из этих устройств являются сегментируемыми — это означает, что их дисковое про­
    странство можно разбить на несколько файловых систем, каждой из которых можно управлять отдельно. В Linux поддерживаются самые разные файловые системы, решительно любые, которые могут встретиться среднему пользователю на практике. В частности, Linux поддерживает файловые системы, специфичные для определенных носителей (например, ISO9660), сетевые файловые системы
    (NFS), нативные файловые системы (ext4), файловые системы из других разно­
    видностей UNIX (XFS), а также файловые системы, не относящиеся к семейству
    UNIX (FAT).
    Наименьшим адресуемым элементом блочного устройства является сектор.
    Сектор — это физический атрибут устройства. Объем секторов может быть равен различным степеням двойки, довольно распространены секторы размером 512 байт.
    Блочное устройство не может передавать элемент данных размером меньше, чем сектор этого устройства, а также не может получать доступ к такому мелкому фрагменту данных. При операциях ввода­вывода должны задействоваться один или несколько секторов.
    Аналогично, наименьшим логически адресуемым элементом файловой системы является блок. Блок — это абстракция, применяемая в файловой системе, а не на физическом носителе, на котором эта система находится. Обычно размер блока равен степени двойки от размера сектора. В Linux блоки, как правило, крупнее сектора, но они должны быть меньше размера страницы (под страницей в модели памяти Linux понимается наименьший элемент, адресуемый блоком управления
    памятью — аппаратным компонентом)
    1
    . Размеры большинства блоков составляют
    512 байт, 1 Кбайт и 4 Кбайт.
    Исторически в системах UNIX было только одно разделяемое пространство имен, видимое для всех пользователей и всех процессов в системе. В Linux исполь­
    зуется инновационный подход и поддерживаются пространства имен отдельных
    процессов. В таком случае каждый процесс может иметь уникальное представление
    1
    Это искусственное ограничение возможностей ядра, установленное ради обеспечения простоты с учетом, что в будущем, возможно, системы значительно усложнятся.
    Глава 1. Введение и основополагающие концепции

    45
    файла системы и иерархии каталогов
    1
    . По умолчанию каждый процесс наследует пространство имен своего родительского процесса, но процесс также может создать собственное пространство имен со своим набором точек монтирования и уникаль­
    ным корневым каталогом.
    Процессы
    Если файлы являются самой фундаментальной абстракцией системы UNIX, то следующая по важности — процесс. Процессы — это объектный код, находящийся в процессе исполнения: активные, работающие программы. Однако процессы — это не просто объектный код, так как они состоят из данных, ресурсов, состояния и вир­
    туализованного процессора.
    Процесс начинает свой жизненный цикл в качестве исполняемого объектного кода. Это код в формате, пригодном для исполнения на машине и понятный ядру.
    Наиболее распространенный подобный формат в Linux называется форматом ис­
    полняемых и компонуемых файлов (ELF). Исполняемый формат содержит мета­
    данные и множество разделов с кодом и данными. Разделы — это линейные фраг­
    менты объектного кода, именно в такой линейной форме загружаемые в память.
    Все байты одного раздела обрабатываются одинаково, имеют одни и те же права доступа и, как правило, используются в одних и тех же целях.
    К самым важным и распространенным разделам относятся текстовый раздел, раздел данных и раздел bss. В текстовом разделе содержатся исполняемый код и данные только для чтения, в частности константные переменные. Обычно этот раздел помечается как доступный только для чтения и исполняемый. В разделе данных хранятся инициализированные данные (например, переменные C с опре­
    деленными значениями). Обычно этот раздел помечается как доступный для чтения и записи. Раздел bss содержит неинициализированные глобальные данные. Стан­
    дарт C требует, чтобы все глобальные переменные C по умолчанию инициализи­
    ровались нулями, поэтому нет необходимости хранить нули в объектном коде на диске. Вместо этого объектный код может просто перечислять неинициализиро­
    ванные переменные в разделе bss, а при загрузке раздела в память ядро отобразит на него нулевую страницу (страницу, содержащую только нули). Раздел bss заду­
    мывался исключительно в качестве оптимизации. Название bss, в сущности, является пережитком, оно означает block started by symbol (блок, начинающийся с символа). Другими примерами распространенных разделов исполняемых файлов в формате ELF являются абсолютный раздел (содержащий неперемещаемые сим­
    волы) и неопределенный раздел, также называемый общей корзиной (catchall).
    Кроме того, процесс ассоциирован с различными системными ресурсами, кото­
    рые выделяются и управляются ядром. Как правило, процессы запрашивают ре­
    сурсы и манипулируют ими только посредством системных вызовов. К ресурсам относятся таймеры, ожидающие сигналы, открытые файлы, сетевые соединения,
    1
    Этот подход был впервые реализован в операционной системе Plan 9 производства
    BellLabs.
    Концепции программирования в Linux

    46
    аппаратное обеспечение и механизмы межпроцессного взаимодействия. Ресурсы процесса, а также относящиеся к нему данные и статистика сохраняются внутри ядра в дескрипторе процесса.
    Процесс — это абстракция виртуализации. Ядро Linux поддерживает как вытес­
    няющую многозадачность, так и виртуальную память, поэтому предоставляет каж­
    дому процессу и виртуализованный процессор, и виртуализованное представление памяти. Таким образом, с точки зрения процесса система выглядит так, как будто только он ею управляет. Соответственно, даже если конкретный процесс может быть диспетчеризован наряду со многими другими процессами, он работает так, как буд­
    то он один обладает полным контролем над системой. Ядро незаметно и прозрачно вытесняет и переназначает процессы, совместно используя системные процессоры на всех работающих процессах данной системы. Процессы этого даже не знают.
    Аналогичным образом каждый процесс получает отдельное линейное адресное про­
    странство, как если бы он один контролировал всю память, доступную в системе.
    С помощью виртуальной памяти и подкачки страниц ядро обеспечивает одновре­
    менное сосуществование сразу многих процессов в системе. Каждый процесс при этом работает в собственном адресном пространстве. Ядро управляет такой виртуа­
    лизацией, опираясь на аппаратную поддержку, обеспечиваемую многими современ­
    ными процессорами. Таким образом, операционная система может параллельно управлять состоянием множественных, не зависящих друг от друга процессов.
    Потоки
    Каждый процесс состоит из одного или нескольких потоков выполнения, обычно называемых просто потоками. Поток — это единица активности в процессе. Можно также сказать, что поток — это абстракция, отвечающая за выполнение кода и под­
    держку процесса в рабочем состоянии.
    Большинство процессов состоят только из одного потока и именуются однопо-
    точными. Если процесс содержит несколько потоков, его принято называть мно-
    гопоточным. Традиционно программы UNIX являются однопоточными, это свя­
    зано с присущей UNIX простотой, быстрым созданием процессов и надежными механизмами межпроцессного взаимодействия. По всем этим причинам многопо­
    точность не имеет в UNIX существенного значения.
    Поток состоит из стека (в котором хранятся локальные переменные этого про­
    цесса, точно как в стеке процесса, используемом в однопоточных системах), состоя­
    ния процесса и актуального местоположения в объектном коде. Информация об этом местоположении обычно хранится в указателе команд процесса. Большинство остальных элементов процесса разделяются между всеми его потоками, особенно это касается адресного пространства. Таким образом, потоки совместно используют абстракцию виртуальной памяти, поддерживая абстракцию виртуализованного процессора.
    На внутрисистемном уровне в ядре Linux реализуется уникальная разновидность потоков: фактически они представляют собой обычные процессы, которые по мере необходимости разделяют определенные ресурсы. В пользовательском простран­
    стве Linux реализует потоки в соответствии со стандартом POSIX 1003.1c (также
    Глава 1. Введение и основополагающие концепции

    47
    называемым Pthreads). Самый современный вариант реализации потоков в Linux именуется Native POSIX Threading Library (NPTL). Эта библиотека входит в состав glibc
    . Подробнее мы поговорим о потоках в гл. 7.
    Иерархия процессов
    Для идентификации каждого процесса применяется уникальное положительное целое число, называемое идентификатором процесса, или ID процесса (pid). Таким образом, первый процесс имеет идентификатор
    1
    , а каждый последующий процесс получает новый, уникальный pid.
    В Linux процессы образуют строгую иерархию, называемую деревом процессов.
    Корень дерева находится в первом процессе, называемом процессом инициализации и обычно принадлежащем программе init
    . Новые процессы создаются с помощью системного вызова fork()
    . В результате этого вызова создается дубликат вызыва­
    ющего процесса. Исходный процесс называется предком, а порожденный — потом-
    ком. У каждого процесса, кроме самого первого, есть свой предок. Если родительский процесс завершается раньше дочернего (потомка), то ядро переназначает предка для потомка, делая его потомком процесса инициализации.
    Когда процесс завершается, он еще какое­то время остается в системе. Ядро сохраняет фрагменты процесса в памяти, обеспечивая процессу­предку доступ к информации о процессе­потомке, актуальной на момент завершения потомка.
    Такое запрашивание называется обслуживанием завершенного процесса. Когда родительский процесс обслужит дочерний, последний полностью удаляется. Про­
    цесс, который уже завершился, но еще не был обслужен, называется зомби. Ини­
    циализирующий процесс по порядку обслуживает все свои дочерние процессы, гарантируя, что процессы с переназначенными родителями не останутся в состоя­
    нии зомби на неопределенный срок.
    Пользователи и группы
    Авторизация в Linux обеспечивается с помощью системы пользователей и групп.
    Каждому пользователю присваивается уникальное положительное целое число, называемое пользовательским ID (uid). Каждый процесс, в свою очередь, ассоци­
    ируется ровно с одним uid, обозначающим пользователя, который запустил процесс.
    Этот идентификатор называется реальным uid процесса. Внутри ядра Linux uid является единственной концепцией, представляющей пользователя. Однако поль­
    зователи называют себя и обращаются к другим пользователям по именам пользо-
    вателей (username), а не по числовым значениям. Пользовательские имена и соот­
    ветствующие им uid сохраняются в каталоге
    /etc/passwd
    , а библиотечные процедуры сопоставляют предоставленные пользователями имена и соответствующие uid.
    При входе в систему пользователь вводит свое имя и пароль в программу входа
    (
    login
    ). Если эта программа получает верную пару, состоящую из логина и пароля, то login порождает пользовательскую оболочку входа, также указываемую в
    /etc/
    passwd
    , и делает uid оболочки равным uid вошедшего пользователя. Процессы­по­
    томки наследуют uid своих предков.
    Концепции программирования в Linux

    48
    Uid
    0
    соответствует особому пользователю, который называется root. Этот поль­
    зователь обладает особыми привилегиями и может делать в системе практически что угодно. Например, только root­пользователь имеет право изменить uid процес­
    са. Следовательно, программа входа (
    login
    ) работает как root.
    Кроме реального uid, каждый процесс также обладает действительным uid,
    сохраненным uid и uid файловой системы. В то время как реальный uid процесса всегда совпадает с uid пользователя, запустившего процесс, действительный uid может изменяться по определенным правилам, чтобы процесс мог выполняться с правами, соответствующими различным пользователям. В сохраненном uid за­
    писывается исходный действительный uid; его значение используется при опреде­
    лении, на какие значения действительного uid может переключаться пользователь.
    Uid файловой системы, который, как правило, равен действительному uid, исполь­
    зуется для верификации доступа к файловой системе.
    Каждый пользователь может принадлежать к одной или нескольким группам, в частности к первичной группе, она же группа входа в систему, указанной в
    /etc/
    passwd
    , а также к нескольким дополнительным группам, которые перечисляются в
    /etc/group
    . Таким образом, каждый процесс ассоциируется с соответствующим
    групповым ID (gid) и имеет действительный gid, сохраненный gid и gid файловой
    системы. Обычно процессы ассоциированы с пользовательской группой входа, а не с какими­либо дополнительными группами.
    Определенные проверки безопасности позволяют процессам выполнять те или иные операции лишь при условии, что процесс соответствует заданным критериям.
    Исторически это решение в UNIX было жестко детерминированным: процессы с uid
    0
    имели доступ, а остальные — нет. Сравнительно недавно в Linux эта система была заменена более универсальной, в которой используется концепция возможно-
    стей (capabilities). Вместо обычной двоичной проверки ядро, с учетом возможностей, может предоставлять доступ на базе гораздо более филигранных настроек.
    Права доступа
    Стандартный механизм прав доступа и безопасности в Linux остался таким же, каким изначально был в UNIX.
    Каждый файл ассоциирован с пользователем­владельцем, владеющей группой и тремя наборами битов доступа. Эти биты описывают права пользователя­вла­
    дельца, владеющей группы и всех остальных, связанные с чтением файла, записью в него и его исполнением. На каждый из этих трех классов действий приходится по три бита, всего имеем девять бит. Информация о владельце файла и правах хранится в индексном дескрипторе файла.
    В случае с обычными файлами назначение прав доступа кажется очевидным: они регламентируют возможности открытия файла для чтения, открытия для записи и исполнения файла. Права доступа, связанные с чтением и записью, аналогичны для обычных и специальных файлов, но сама информация, которая считывается из спе­
    циального файла или записывается в него, зависит от разновидности специального файла. Например, если предоставляется доступ к каталогу для чтения, это означает,
    Глава 1. Введение и основополагающие концепции

    1   2   3   4   5   6   7   8   9   ...   14


    написать администратору сайта