Отношения оболочки и ядра

Прежде чем обсуждать, что происходит, когда мы набираем «ls -l» в оболочке, почему возникает такой вопрос? Цель оболочки — предоставить нам средства для связи с программой, управляющей всеми программами на машине, ядром. Оболочка действует как посредник между пользователем и ядром. Таким образом, ядро ​​может сосредоточиться на выполнении, в то время как оболочка работает над интерпретацией пользовательских запросов. Оболочка интерпретирует то, что вводит пользователь, как потенциальные аргументы команды, которые идентифицируются и выполняются соответственно.

Интерпретация

Как оболочка идентифицирует ввод пользователя как команду? Он начинается с чтения стандартного ввода, введенного пользователем, в нашем случае «ls -l» (он также может читать файл как ввод неинтерактивно). Чтение выполняется функцией getline(), которая сохраняет введенные данные в виде строки. Затем функция strtok() разделяет введенные аргументы, используя идентификатор разделения или разделитель. Обычно пробелы действуют как разделитель, так как все аргументы должны быть разделены пробелами. Ваш ввод теперь будет «токенизирован» как массив строк.

How ls -l would be tokenized: { "ls", "-l", NULL }

Следующий шаг — посмотреть, является ли ваша команда ввода псевдонимом или ее нужно расширить. Псевдоним — это определяемый пользователем ярлык для конкретной команды, к которой мы его привязали. Таким образом, если мы найдем псевдоним, оболочка преобразует псевдоним в команду, которую он представляет, до того, как ядро ​​получит его.

Suppose we wanted to make an alias for "ls -l" and call it "long":
#cisfun$ alias long="ls -l"

Расширение проверяет, содержит ли ваш аргумент специальные символы, которые сообщают оболочке, что аргумент должен быть расшифрован для полной интерпретации. Например, подстановочный знак «*» может использоваться для расширения нескольких разных аргументов с одним и тем же именем или использования «$» для отображения переменных среды, идентификаторов процессов, номеров состояний команд и т. д.

Suppose we had a variable named "FEELING" with the value "happy", then we could expand it to find the value by:
#cisfun$ echo $FEELING
#cisfun$ happy

Расположение команды

Затем оболочка проверяет, является ли команда встроенной, командной функцией, созданной и готовой к выполнению непосредственно внутри оболочки. Если команды там нет, то оболочка вызывает переменную окружения с именем «PATH». Эта переменная содержит набор каталогов, в которых организованы исполняемые файлы, чтобы оболочка могла легко найти команду, необходимую пользователю.

Если он найден, он прикрепляет к команде путь к каталогу и передает его ядру для выполнения. Например, команда «ls» — это исполняемый файл в каталоге «/bin» из PATH. Таким образом, оболочка объединит каталог и команду и передаст ядру «/bin/ls».

Системные вызовы ядра

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

  1. вилка()
  2. выполнить()
  3. ждать()

Ядро поддерживает выполнение различных программ, имея для них процессы. Однако, поскольку он занят поддержанием своего собственного процесса, для выполнения команды необходимо создать дочерний процесс, который наследует ту же среду, что и текущий процесс. Дочерний процесс создается путем клонирования текущего процесса, это обрабатывается функцией fork(). После разветвления execve() выполняет имя файла, которое было интерпретировано оболочкой (включая любые следующие параметры, такие как «-l»). Функция wait() просто приостанавливает исходный процесс (называемый родительским процессом) до тех пор, пока его выполнение не завершится или не завершится ошибкой. Это позволяет родительскому процессу отслеживать дочерний процесс, а затем продолжать свой собственный процесс после завершения дочернего процесса. Таким образом, наш «/bin/ls -l» будет вызываться в execve(). После завершения дочернего процесса родительский процесс готов к выполнению другой команды. Он отобразит переменную среды PS1, обычно «$», и будет ждать, пока пользователь введет другую команду.

Подведение итогов

Давайте повторим, что мы узнали. На рисунке блок-схемы показан логический поток процесса оболочки. Оболочка печатает приглашение и ожидает ввода командной строки. После ввода он читается и расширяется, удаляя ненужные значения, такие как комментарии. Затем мы проверяем, является ли команда встроенной, и если да, то выполняем ее. Если нет, мы проверяем, находится ли он в PATH. Если это так, мы создаем дочерний процесс и выполняем его. Как только дочернее выполнение завершено, родительский процесс продолжается и готов к следующему пользовательскому вводу!

АВТОРЫ

Брент Муха, Судип Радж

Вот ссылка на репозиторий сделанной нами оболочки!