рефераты конспекты курсовые дипломные лекции шпоры

Реферат Курсовая Конспект

Замена образа процесса

Замена образа процесса - раздел Программирование, Программирование для операционной системы Linux Итак, Теперь Мы Умеем Порождать Процессы. Научимся Теперь Заменять Образ Теку...

Итак, теперь мы умеем порождать процессы. Научимся теперь заменять образ текущего процесса другой программой. Для этих целей используется системный вызов execve(), который объявлен в заголовочном файле unistd.h вот так:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int execve (const char * path, char const * argv[], char * const envp[]);

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Все очень просто: системный вызов execve() заменяет текущий образ процесса программой из файла с именем path, набором аргументов argv и окружением envp. Здесь следует только учитывать, что path–это не просто имя программы, а путь к ней. Иными словами, чтобы запустить ls, нужно в первом аргументе указать "/bin/ls".

Массивы строк argv и envp обязательно должны заканчиваться элементом NULL. Кроме того, следует помнить, что первый элемент массива argv (argv[0]) - это имя программы или что-либо иное. Непосредственные аргументы программы отсчитываются от элемента с номером 1.

В случае успешного завершения execve() ничего не возвращает, поскольку новая программа получает полное и безвозвратное управление текущим процессом. Если произошла ошибка, то по традиции возвращается -1.

Рассмотрим теперь пример программы, которая заменяет свой образ другой программой.

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/* execve01.c */

#include <unistd.h>

#include <stdio.h>

 

int main (void)

{

printf ("pid=%dn", getpid ());

execve ("/bin/cat", NULL, NULL);

 

return 0;

}

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

И так, данная программа выводит свой PID и передает безвозвратное управление программе cat без аргументов и без окружения.

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ gcc -o execve01 execve01.c

$ ./execve01

pid=30150

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

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

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ ps -e | grep 30150

30150 pts/3 00:00:00 cat

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Итак, мы убедились, что теперь процесс 30150 выполняет программа cat. Теперь можно вернуться в исходное окно и нажатием Ctrl+D завершить работу cat.

И, наконец, следующий пример демонстрирует запуск программы в отдельном процессе.

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/* forkexec01.c */

#include <unistd.h>

#include <stdio.h>

 

extern char ** environ;

 

int main (void)

{

char * echo_args[] = { "echo", "child", NULL };

 

if (!fork ()) {

execve ("/bin/echo", echo_args, environ);

fprintf (stderr, "an error occuredn");

return 1;

}

 

printf ("parent");

return 0;

}

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Проверяем:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ gcc -o forkexec01 forkexec01.c

$ ./forkexec01

parent

child

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Обратите внимание, что поскольку execve() не может возвращать ничего кроме -1, то для обработки возможной ошибки вовсе необязательно создавать ветвление. Иными словами, если вызов execve() возвратил что-то, то это однозначно ошибка.

 

Функции семейства exec()

Давайте теперь посмотрим на прототип системного вызова execve() критически. Он принимает три аргумента, которые не всегда удобно использовать. Первый аргумент может не устраивать нас из-за того, что требует непременно указывать точный путь к исполняемому файлу, а это не всегда удобно. Второй аргумент - массив строк: тоже не всегда удобно. Хотелось бы иметь возможность передавать строки напрямую в функцию. Третий аргумент зачастую вообще не требуется, поскольку дочерние процессы обычно работают с копией окружения своих родителей.

Чтобы программисту каждый раз при замене образа процесса не приходилось "подгонять" аргументы под прототип execve(), были реализованы библиотечные надстройки над execve(), которые обычно называют семейством exec().

Эти надстройки представляют собой пять функций, объявленных в заголовочном файле unistd.h, которые позволяют манипулировать различными комбинациями аргументов. Хотя функции семейства exec() не являются системными вызовами, но их прототипы жестко прописаны в стандарте POSIX и, следовательно, они совместимы с большинством современных Unix-систем.

Первая функция семейства - execl(). Ниже представлен ее прототип.

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int execl (const char * path, const char * arg, ...);

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

В этой функции первый аргумент такой же, как и в execve() –путь к файлу относительно текущего или корневого каталога. А дальше идет список аргументов, передаваемых программе в виде отдельных аргументов. Список должен заканчиваться аргументом NULL. Этот вариант exec() не требует явно задавать окружение: программа просто получает окружение родителя. В следующем примере показана программа из предыдущего раздела (forkexec01.c), но переписанная под использование execl().

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/* forkexec02.c */

#include <unistd.h>

#include <stdio.h>

 

int main (void)

{

if (!fork ()) {

execl ("/bin/echo", "echo", "child", NULL);

fprintf (stderr, "an error occuredn");

return 1;

}

 

return 0;

}

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Следующая функция семейства - execlp(). Она работает аналогично функции execl(), но в качестве первого аргумента может принимать не только путь к исполняемому файлу, но так же и просто имя программы из каталога, обозначенного в переменной окружения PATH. Иными словами, теперь вместо /bin/echo мы можем писать просто echo. Ниже показан прототип функции execlp().

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int execlp (constchar * file, constchar * arg, ...);

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Теперь рассмотрим версию программы forkexec02.c, в которой используется execlp().

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/* forkexec03.c */

#include <unistd.h>

#include <stdio.h>

 

int main (void)

{

if (!fork ()) {

execlp ("echo", "echo", "child", NULL);

fprintf (stderr, "an error occuredn");

return 1;

}

 

return 0;

}

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Еще одна функция семейства - execle(). Эта функция, подобноexecl() и execve(), не читает переменную PATH и использует в качестве первого аргумента путь к исполняемому файлу. Как и в execl() здесь аргументы задаются не массивом, а списком, оканчивающимся элементом NULL, однако после этого списка идет еще один аргумент, задающий окружение будущей программы. Ниже представлен прототип функции execle().

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int execle (const char * path, const char * arg, ..., char * const envp[]);

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Ниже показана модифицированная версия программы forkexec03.c, использующая execle() для замены образа процесса.

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/* forkexec04.c */

#include <unistd.h>

#include <stdio.h>

 

extern char ** environ;

 

int main (void)

{

if (!fork ()) {

execle ("/bin/echo", "echo", "child", NULL, environ);

fprintf (stderr, "an error occuredn");

return 1;

}

 

return 0;

}

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Следующая функция - execv(). Она работает также, как и execve(), но только без последнего аргумента, задающего окружение. Ниже представлен прототип execv().

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int execv (const char * path, char * const argv[]);

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Ниже показан пример, демонстрирующий работу execv().

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/* forkexec05.c */

#include <unistd.h>

#include <stdio.h>

 

int main (void)

{

char * echo_args[] = { "echo", "child", NULL };

if (!fork ()) {

execv ("/bin/echo", echo_args);

fprintf (stderr, "an error occuredn");

return 1;

}

 

return 0;

}

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

И осталась последняя функция семейства - execvp(). Эта функция работает аналогично execv(), но в качестве первого аргумента может принимать не только путь, но и имя файла, находящегося в одном из каталогов, перечисленных в переменной окружения PATH. Вот прототип этой функции.

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int execvp (const char * file, char * const argv[]);

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

А вот пример работы execvp().

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/* forkexec06.c */

#include <unistd.h>

#include <stdio.h>

 

int main (void)

{

char * echo_args[] = { "echo", "child", NULL };

if (!fork ()) {

execvp ("echo", echo_args);

fprintf (stderr, "an error occuredn");

return 1;

}

 

return 0;

}

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Не запутаться в названиях функций семейства exec() позволяет простое правило. Нужно лишь запомнить, какой постфикс из набора "l, v, e, p" за что отвечает. Итак, наличие "l" говорит о том, что набор аргументов запускаемой программы представлен не массивом, а отдельными строками. Противоположность "l" - постфикс "v", который сообщает, что список аргументов запускаемой программы передается в виде массива. Постфикс "e" говорит о том, что через последний аргумент функции запускаемой программе передается массив окружения. Постфикс "p" говорит о том, что в первом аргументе функции можно использовать не только путь к исполняемому файлу, а просто имя этого файла, при условии, что файл находится в одном из каталогов, обозначенных в переменной окружения PATH. Отсутствие "p" сообщает о том, что поиск по PATH не производится. Как видите, системный вызов execve() тоже отвечает этому правилу.

 

– Конец работы –

Эта тема принадлежит разделу:

Программирование для операционной системы Linux

Министерство образования и науки РФ... Федеральное агентство по образованию... Государственное образовательное учреждение высшего профессионального образования...

Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ: Замена образа процесса

Что будем делать с полученным материалом:

Если этот материал оказался полезным ля Вас, Вы можете сохранить его на свою страничку в социальных сетях:

Все темы данного раздела:

Процессы в Linux
В жизни обычного пользователя Linux часто встречается термин «процессы». Так что же такое «процесс»? Попробуем разобраться. Сухая формулировка говорит нам, что процесс - это совокупность п

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

Обзор механизмов ввода-вывода в Linux
В языке C для осуществления файлового ввода-вывода используются механизмы стандартной библиотеки языка, объявленные в заголовочном файле stdio.h. Как вы вскоре узнаете консольный ввод-вывод - это н

Файловые дескрипторы
В языке C при осуществлении ввода-вывода мы используем указатель FILE*. Даже функция printf() в итоге сводится к вызову vfprintf(stdout,...), разновидности функции fprintf(); константа stdout имеет

МНОГОЗАДАЧНОСТЬ
Операционная система Linux является многозадачной. За многозадачность отвечает ядро. Что же представляет собой многозадачность? Мы привыкли под этим термином понимать концепцию одновременного выпол

Основы многозадачности в Linux
Наберите в своей оболочке следующую команду: −−−−−−−−−−−−−−−−−−−−

Порождение процесса
Как уже говорилось ранее, процесс в Linux - это нечто, выполняющее программный код. Этот код называют образом процесса (process image). Рассмотрим простой пример, когда вы находитесь в оболочке bas

Типы файлов
Файловая система в Linux многих пугает своей мнимой сложностью. Устройства, ссылки, "иноды", права доступа: всё это кажется очень непонятным. На самом же деле, если все "разложить по

Режим файла
Под режимом файла (file mode) понимается связанный непосредственно с индексным дескриптором (а не со ссылкой) 16-битный набор, регламентирующий порядок доступа и работы с файлом. Иногда режим файла

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

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

Хотите получать на электронную почту самые свежие новости?
Education Insider Sample
Подпишитесь на Нашу рассылку
Наша политика приватности обеспечивает 100% безопасность и анонимность Ваших E-Mail
Реклама
Соответствующий теме материал
  • Похожее
  • Популярное
  • Облако тегов
  • Здесь
  • Временно
  • Пусто
Теги