Системный вызов Linux Exec

Linux Exec System Call



Системный вызов exec используется для выполнения файла, находящегося в активном процессе. При вызове exec предыдущий исполняемый файл заменяется и выполняется новый файл.

Точнее, мы можем сказать, что использование системного вызова exec заменит старый файл или программу из процесса новым файлом или программой. Все содержание процесса заменяется новой программой.







Сегмент пользовательских данных, который выполняет системный вызов exec (), заменяется файлом данных, имя которого указывается в аргументе при вызове exec ().



Новая программа загружается в то же пространство процесса. Текущий процесс просто превращается в новый процесс, и, следовательно, идентификатор PID процесса не изменяется, это потому, что мы не создаем новый процесс, мы просто заменяем процесс другим процессом в exec.



Если текущий запущенный процесс содержит более одного потока, все потоки будут завершены, а новый образ процесса будет загружен и затем выполнен. Нет функций деструктора, которые завершают потоки текущего процесса.





PID процесса не изменяется, но данные, код, стек, куча и т. Д. Процесса изменяются и заменяются данными вновь загруженного процесса. Новый процесс выполняется с точки входа.

Системный вызов Exec - это набор функций, и на языке программирования C стандартные имена этих функций следующие:



  1. execl
  2. экзекль
  3. execlp
  4. execv
  5. Execve
  6. execvp


Здесь следует отметить, что эти функции имеют одинаковую базу exec за которым следует одна или несколько букв. Это объясняется ниже:

А также: Это массив указателей, который указывает на переменные среды и явно передается вновь загруженному процессу.

в: l для аргументов командной строки передается список функции

п: p - это переменная среды пути, которая помогает найти файл, переданный в качестве аргумента для загрузки в процесс.

v: v - для аргументов командной строки. Они передаются в виде массива указателей на функцию.

Почему используется exec?

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

Внутренняя работа exec

Чтобы понять, как работает exec, обратите внимание на следующие моменты:

  1. Текущий образ процесса перезаписывается новым образом процесса.
  2. Новый образ процесса - это тот, который вы передали в качестве аргумента exec
  3. Текущий процесс завершен
  4. Новый образ процесса имеет тот же идентификатор процесса, ту же среду и тот же дескриптор файла (поскольку процесс не заменяется, образ процесса заменяется)
  5. Это влияет на статистику ЦП и виртуальную память. Отображение виртуальной памяти текущего образа процесса заменяется виртуальной памятью нового образа процесса.

Синтаксисы функций семейства exec:

Ниже приведены синтаксисы для каждой функции exec:

int execl (const char * путь, const char * arg,…)
int execlp (const char * файл, const char * arg,…)
int execle (const char * путь, const char * arg,…, char * const envp [])
int execv (const char * путь, const char * argv [])
int execvp (const char * файл, const char * argv [])
int execvpe (const char * файл, const char * argv [], char * const envp [])

Описание:

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

В синтаксисе:

  1. дорожка используется для указания полного пути к исполняемому файлу.
  1. злой переданный аргумент. На самом деле это имя файла, который будет выполняться в процессе. В большинстве случаев значения arg и path одинаковы.
  1. const char * arg в функциях execl (), execlp () и execle () рассматривается как arg0, arg1, arg2,…, argn. По сути, это список указателей на строки с завершающим нулем. Здесь первый аргумент указывает на имя файла, которое будет выполнено, как описано в пункте 2.
  1. envp представляет собой массив, содержащий указатели, указывающие на переменные среды.
  1. файл используется для указания имени пути, которое будет определять путь к новому файлу образа процесса.
  1. Функции вызова exec, заканчивающиеся на А также используются для изменения среды для нового образа процесса. Эти функции передают список настроек среды с помощью аргумента envp . Этот аргумент представляет собой массив символов, который указывает на строку с завершающим нулем и определяет переменную среды.

Чтобы использовать функции семейства exec, вам необходимо включить следующий файл заголовка в вашу программу C:

#включают

Пример 1: Использование системного вызова exec в программе на C

Рассмотрим следующий пример, в котором мы использовали системный вызов exec при программировании на C в Linux, Ubuntu: У нас есть два файла c, example.c и hello.c:

example.c

КОД:

#включают
#включают
#включают
intглавный(intargc, char *argv[])
{
printf ('PID example.c =% d п',Getpid());
char *аргументы[] знак равно {'Привет', 'C', 'Программирование',НУЛЕВОЙ};
execv('./Привет',аргументы);
printf ('Вернуться к example.c');
возвращение 0;
}

Привет

КОД:

#включают
#включают
#включают
intглавный(intargc, char *argv[])
{
printf ('Мы в Hello.c п');
printf ('PID hello.c =% d п',Getpid());
возвращение 0;
}

ВЫХОД:

PID example.c = 4733
Мы в Hello.c
PID hello.c = 4733

В приведенном выше примере у нас есть файлы example.c и hello.c. В примере файла .c в первую очередь мы напечатали идентификатор текущего процесса (файл example.c запущен в текущем процессе). Затем в следующей строке мы создали массив символьных указателей. Последний элемент этого массива должен иметь значение NULL в качестве конечной точки.

Затем мы использовали функцию execv (), которая принимает в качестве аргумента имя файла и массив символьных указателей. Здесь следует отметить, что мы использовали ./ с именем файла, он указывает путь к файлу. Поскольку файл находится в папке, где находится example.c, нет необходимости указывать полный путь.

Когда вызывается функция execv (), наш образ процесса будет заменен, теперь файл example.c не находится в процессе, а файл hello.c находится в процессе. Можно видеть, что идентификатор процесса один и тот же, независимо от того, является ли hello.c образом процессом или example.c является образом процесса, потому что процесс такой же, а образ процесса только заменяется.

Затем у нас есть еще одна вещь, на которую следует обратить внимание, а именно оператор printf () после того, как execv () не выполняется. Это связано с тем, что управление никогда не возвращается обратно к старому образу процесса, если его заменяет новый образ процесса. Управление возвращается к вызывающей функции только в том случае, если замена образа процесса не удалась. (В данном случае возвращаемое значение - -1).

Разница между системными вызовами fork () и exec ():

Системный вызов fork () используется для создания точной копии запущенного процесса, и созданная копия является дочерним процессом, а запущенный процесс является родительским процессом. В то время как системный вызов exec () используется для замены образа процесса новым образом процесса. Следовательно, в системном вызове exec () нет концепции родительских и дочерних процессов.

В системном вызове fork () родительский и дочерний процессы выполняются одновременно. Но в системном вызове exec (), если замена образа процесса прошла успешно, управление не вернется туда, где была вызвана функция exec, а выполнит новый процесс. Управление будет передано обратно только в случае ошибки.

Пример 2: Объединение системных вызовов fork () и exec ()

Рассмотрим следующий пример, в котором мы использовали системные вызовы fork () и exec () в одной программе:

example.c

КОД:

#включают
#включают
#включают
intглавный(intargc, char *argv[])
{
printf ('PID example.c =% d п',Getpid());
pid_t p;
пзнак равновилка();
если(п== -1)
{
printf ('Ошибка при вызове fork ()');
}
если(п==0)
{
printf ('Мы находимся в дочернем процессе п');
printf ('Вызов hello.c из дочернего процесса п');
char *аргументы[] знак равно {'Привет', 'C', 'Программирование',НУЛЕВОЙ};
execv('./Привет',аргументы);
}
еще
{
printf ('Мы находимся в родительском процессе');
}
возвращение 0;
}

Привет:

КОД:

#включают
#включают
#включают
intглавный(intargc, char *argv[])
{
printf ('Мы в Hello.c п');
printf ('PID hello.c =% d п',Getpid());
возвращение 0;
}

ВЫХОД:

PID example.c = 4790
Мы находимся в родительском процессе
Мы находимся в дочернем процессе
Вызов hello.c из дочернего процесса
Мы в hello.c
PID hello.c = 4791

В этом примере мы использовали системный вызов fork (). Когда дочерний процесс будет создан, 0 будет присвоен p, а затем мы перейдем к дочернему процессу. Теперь будет выполнен блок операторов с if (p == 0). Отображается сообщение, и мы использовали системный вызов execv (), и текущий образ дочернего процесса, который является example.c, будет заменен на hello.c. Перед вызовом execv () дочерний и родительский процессы были одинаковыми.

Видно, что PID example.c и hello.c теперь другой. Это потому, что example.c - это образ родительского процесса, а hello.c - образ дочернего процесса.