Разработка приложений в среде Linux. Второе издание
Шрифт:
Для многих кодов возврата ошибок даны примеры одного или двух системных вызовов, которые обычно могут выдать то или иное сообщение об ошибке. Это не означает, что к таким ошибкам могут привести исключительно представленные системные вызовы.
Для определения того, какую ошибку можно ожидать от определенного системного вызова, обращайтесь к соответствующим man-страницам. В частности, с помощью команды
E2BIG | Список аргументов слишком длинный. При запуске нового процесса с помощью exec существует ограничение на длину задаваемого списка аргументов. См. главу 10. |
EACCESS | В доступе будет отказано. Эта ошибка возвращается системным вызовом access , рассматриваемым в главе 11, и представляет собой более информативный код возврата, чем само состояние ошибки. |
EAGAIN | Возвращается при попытке выполнения неблокируемого ввода-вывода, если нет доступных данных. EWOULDBLOCK
EAGAIN . При блокируемом вводе-выводе системный вызов установил бы блокировку и ожидал бы данных. |
EBADF | Неправильный номер файла. Был передан номер файла, не ссылающийся на открытый файл, в функцию read , close , ioctl или другой системный вызов, принимающий номер файла в качестве аргумента. |
EBUSY | Системный вызов mount возвращает эту ошибку при попытке смонтировать файловую систему, которая уже смонтирована, или размонтировать файловую систему, которая в настоящий момент используется. |
ECHILD | Дочерние процессы отсутствуют. Возвращается семейством системных вызовов wait . См. главу 10. |
EDOM | Это ошибка не системного вызова, а ошибка из библиотеки С системы. EDOM устанавливается математическими функциями, если аргумент выходит за пределы допустимого диапазона. (Это EINVAL для области функции.) Например, функция sqrt не работает с комплексными числами и потому не принимает отрицательные аргументы. |
EEXIST | Возвращается creat , mknod или mkdir , если файл уже существует, или функцией open в том же случае, если указаны флаги O_CREAT и O_EXCL . |
EFAULT | Неверный указатель (указывающий на недоступную область памяти) был передан в качестве аргумента системному вызову. Обращение по этому указателю из пользовательской программы, которая произвела системный вызов, приведет к ошибке сегментации. |
EFBIG | Возвращается write при попытке записи файла, который длиннее, чем может логически обработать файловая система (физические ограничения пространства во внимание не принимаются). |
EINTR | Системный вызов был прерван. Прерываемые системные вызовы рассматриваются в главе 12. |
EINVAL | Возвращается, если системный вызов получил недопустимый аргумент. |
EIO | Ошибка ввода-вывода. Обычно генерируется драйвером устройства для обозначения ошибки в оборудовании или неисправимой ошибку взаимодействия с устройством. |
EISDIR | Возвращается системными вызовами, требующими имя файла, например unlink , если последний компонент в имени пути является каталогом, а не файлом, а данная операция не может быть применена к каталогу. |
ELOOP | Возвращается системными вызовами, которые принимают путь, если при разборе пути встречается слишком много символических ссылок в строке (то есть символические ссылки, указывающие на символические ссылки, которые, в свою очередь, указывают на символические ссылки и так далее). Текущее ограничение — 16 символических ссылок на строку. |
EMFILE | Возвращается, если для вызываемого процесса нельзя открыть больше файлов. |
EMLINK | Возвращается link , если в компонуемом файле уже содержится максимальное количество ссылок для файловой системы (в стандартной файловой системе Linux этот максимум составляет 32 000). |
ENAMETOOLONG | Имя пути слишком длинное либо для системы, либо для файловой системы, к которой вы пытаетесь получить доступ. |
ENFILE | Возвращается, если ни один процесс системы не может открыть больше ни одного файла. |
ENODEV | Возвращается mount , если запрошенный тип файловой системы не доступен. Возвращается open при попытке открыть специальный файл для устройства, для которого нет ассоциированного драйвера в ядре. |
ENOENT | Файл или каталог не существует. Возвращается при попытке получить доступ к несуществующему файлу или каталогу. |
ENOEXEC | Ошибка исполняемого формата. Может появиться при попытке запустить (устаревший) а.out в системе, в которой отсутствует поддержка бинарных файлов а.out . Может также встречаться при попытке запуска бинарного файла формата ELF, собранного для другой архитектуры центрального процессора. |
ENOMEM | Не хватает памяти. Возвращается функциями brk и mmap при неудачной попытке распределения памяти. |
ENOSPC | Возвращается write при попытке записать файл длиннее, чем объем свободного пространства в файловой системе. |
NOSYS | Системный вызов не реализован. Обычно происходит при запуске нового исполняемого файла на старом ядре, которое не поддерживает системный вызов. |
ENOTBLK | Системный вызов mount возвращает эту ошибку при попытке смонтировать в качестве файловой системы файл, не являющийся специальным файлом блочного устройства. |
ENOTDIR | Промежуточный компонент пути существует, но не является каталогом. Возвращается любым системным вызовом, принимающим имя файла. |
ENOTEMPTY | Возвращается rmdir , если удаляемый каталог не пуст. |
ENOTTY | Обычно встречается, когда приложение, которое пытается обратиться к терминалу, запущено с перенаправлением ввода или вывода в канал. Но также может встречаться при попытке совершить операцию ввода-вывода на неправильном типе устройства. Стандартное сообщение об ошибке в этом случае, "not a typewriter", может сбить с толку. |
ENXIO | Нет
|
EPERM | У процесса недостаточно полномочий для завершения операции. Эта ошибка обычно встречается в файловых операциях. См. главу 11. |
EPIPE | Возвращается write , если читающая сторона канала или сокета закрыта и захвачен или проигнорирован сигнал SIGPIPE . См. главу 12. |
ERANGE | Не являясь ошибкой системного вызова, ERANGE устанавливается математическими функциями, если результат невозможно представить возвращаемым типом. Эта ошибка может также возникать в других функциях, если им передается слишком короткий буфер для возвращаемой строки. (Для диапазона этой ошибке соответствует EINVAL .) |
EROFS | Возвращается write при попытке записать в файловую систему, доступную только для чтения. |
ESPIPE | Возвращается lseek при навигации по файлу, дескриптор которого не поддерживает навигацию (включая файловые дескрипторы для каналов, именованных каналов и сокетов). См. главы 11 и 17. |
ESRCH | Нет такого процесса. См. главу 10. |
ETXTBSY | Возвращается open при попытке открыть на запись запущенный исполняемый файл или совместно используемую библиотеку или любой другой файл, отображенный на память с установленным флажком MAP_DENYWRITE (см. главу 13). Чтобы избежать такого поведения, необходимо переименовать файл, сделать новую копию с таким же именем, как у старого файла, и работать с этой новой копией. См. главу 11 с обсуждением того, почему так происходит. |
EXDEV | Возвращается link , если исходные и целевые файлы находятся в разных файловых системах. |
Распространены и некоторые другие коды возврата ошибок, которые относятся только к сетевым функциям. Более подробную информацию можно найти в главе 17.
9.3. Поиск заголовочных и библиотечных файлов
Заголовочные файлы в системе Linux хранятся в иерархии каталогов
С библиотеками дело обстоит практически так же, правда, с некоторыми нюансами. Библиотеки, которые считаются важными для загрузки системы (и ее отладки в случае необходимости), расположены в
Некоторые библиотеки обеспечивают поддержку разработки в одной системе для нескольких основных своих версий. В большинстве случаев доступны специальные утилиты конфигурации, которые обеспечивают включение корректных версий заголовочных файлов и компоновку с подходящими версиями библиотек. Унифицированный инструмент под названием
Часть III
Системное программирование
Глава 10
Модель процессов
Модель процессов — один из "фирменных знаков" Unix. Это — ключ к пониманию прав доступа, отношений между открытыми файлами, сигналов, управления заданиями и большинства других низкоуровневых понятий, описанных в этой книге. Linux адаптирует большую часть модели процессов Unix и добавляет собственные новые идеи, касающиеся реализации облегченных потоков.
10.1. Определение процесса
Что такое процесс? В исходной реализации Unix процессом была любая выполняющаяся программа. Для каждой программы ядро системы отслеживает перечисленные ниже аспекты.
• Текущая точка выполнения (такая как ожидание возврата системного вызова из ядра), часто называемая программным контекстом.
• К каким файлам имеет доступ программа.
• Сертификаты (credentials) программы (например, какой пользователь и группа владеют процессом).
• Текущий каталог программы.
• К какому пространству памяти имеет доступ программа и как оно распределено.
Процесс также является базовой единицей планирования для операционной системы. Только процессам разрешено выполняться в центральном процессоре.
10.1.1. Усложнение концепции — потоки
Хотя определение процесса может показаться очевидным, концепция потока (thread) делает все это несколько менее ясным. Поток позволяет единственной программе выполняться во многих местах одновременно. Все потоки, созданные одной программой, разделяют большинство характеристик, которые отличают процессы друг от друга. Например, множество потоков, порожденных от одной программы, разделяют информацию об открытых файлах, правах доступа, текущем каталоге и образе памяти. Как только один из потоков модифицирует глобальную переменную, все потоки увидят новое значение, а не только тот, что это сделал.
Многие реализации Unix (включая каноническую версию AT&T System V) были перепроектированы, чтобы сделать потоки фундаментальным элементом планирования для ядра, и процесс превратился в коллекцию потоков, разделяющих ресурсы. Поскольку множество ресурсов разделяется между потоками, ядро может быстрее переключаться между потоками одного процесса, чем оно это делает при полноконтекстном переключении между процессами. В результате в большинстве ядер Unix существует двухуровневая модель процессов, которая различает потоки и процессы.
10.1.2. Подход Linux
В Linux, однако, все идет другим путем. Переключение контекстов в Linux всегда было исключительно быстрым (примерно на том же уровне, как новые "переключатели потоков", представленные в двухуровневом подходе), что стимулировало разработчиков ядра вместо смены подхода к планированию процессов позволить процессам разделять ресурсы более либерально.
Под Linux процесс определен исключительно как планируемая сущность, и единственная вещь, которая уникальна для процесса — это текущий контекст выполнения. Он не предполагает ничего относительно разделенных ресурсов, потому что процесс, создающий новый дочерний процесс, имеет полный контроль над тем, какие из ресурсов процессы могут разделять между собой (см. детали в описании системного вызова clone в конце этой главы). Эта модель позволяет сохранять традиционную систему управления процессами Unix, в то время как традиционный интерфейс потоков строится вне ядра.
К счастью, разница между моделью процессов Linux и двухуровневым подходом проявляется редко. В настоящей книге мы используем термин процесс для обозначения набора из (обычно, одной) планируемых сущностей, которые разделяют основные ресурсы. Когда процесс состоит из одного потока, мы используем эти термины как взаимозаменяемые. Чтобы не усложнять, в большей части этой главы мы будем игнорировать потоки полностью. До ее завершения мы обсудим системный вызов