Московский физико-технический институт
Опубликован: 16.09.2004 | Доступ: свободный | Студентов: 7875 / 1661 | Оценка: 4.44 / 4.28 | Длительность: 15:33:00
Лекция 2:

Процессы в операционной системе UNIX

< Лекция 1 || Лекция 2: 1234 || Лекция 3 >

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

Для изменения пользовательского контекста процесса применяется системный вызов exec() , который пользователь не может вызвать непосредственно. Вызов exec() заменяет пользовательский контекст текущего процесса на содержимое некоторого исполняемого файла и устанавливает начальные значения регистров процессора (в том числе устанавливает программный счетчик на начало загружаемой программы). Этот вызов требует для своей работы задания имени исполняемого файла, аргументов командной строки и параметров окружающей среды. Для осуществления вызова программист может воспользоваться одной из шести функций: execlp() , execvp() , execl() и, execv() , execle() , execve() , отличающихся друг от друга представлением параметров, необходимых для работы системного вызова exec() . Взаимосвязь указанных выше функций изображена на рисунке 3–4.3.

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

Рис. 3-4.3. Взаимосвязь различных функций для выполнения системного вызова exec()

Функции изменения пользовательского контекста процесса

Прототипы функций

#include <unistd.h>
int execlp(const char *file, 
    const char *arg0,
... const char *argN,(char *)NULL)
int execvp(const char *file, char *argv[])
int execl(const char *path, 
    const char *arg0,
... const char *argN,(char *)NULL)
int execv(const char *path, char *argv[])
int execle(const char *path, 
    const char *arg0,
... const char *argN,(char *)NULL, 
    char * envp[])
int execve(const char *path, char *argv[], 
    char *envp[])

Описание функций

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

Аргумент file является указателем на имя файла, который должен быть загружен. Аргумент path – это указатель на полный путь к файлу, который должен быть загружен.

Аргументы arg0, ..., argN представляют собой указатели на аргументы командной строки. Заметим, что аргумент arg0 должен указывать на имя загружаемого файла. Аргумент argv представляет собой массив из указателей на аргументы командной строки. Начальный элемент массива должен указывать на имя загружаемой программы, а заканчиваться массив должен элементом, содержащим указатель NULL.

Аргумент envp является массивом указателей на параметры окружающей среды, заданные в виде строк "переменная=строка". Последний элемент этого массива должен содержать указатель NULL.

Поскольку вызов функции не изменяет системный контекст текущего процесса, загруженная программа унаследует от загрузившего ее процесса следующие атрибуты:

  • идентификатор процесса;
  • идентификатор родительского процесса;
  • групповой идентификатор процесса;
  • идентификатор сеанса;
  • время, оставшееся до возникновения сигнала SIGALRM ;
  • текущую рабочую директорию;
  • маску создания файлов;
  • идентификатор пользователя;
  • групповой идентификатор пользователя;
  • явное игнорирование сигналов;
  • таблицу открытых файлов (если для файлового дескриптора не устанавливался признак "закрыть файл при выполнении exec() ").

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

Поскольку системный контекст процесса при вызове exec() остается практически неизменным, большинство атрибутов процесса, доступных пользователю через системные вызовы ( PID , UID, GID, PPID и другие, смысл которых станет понятен по мере углубления наших знаний на дальнейших занятиях), после запуска новой программы также не изменяется.

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

Прогон программы с использованием системного вызова exec()

Для иллюстрации использования системного вызова exec() давайте рассмотрим следующую программу

/* Программа 03-2.с, изменяющая пользователь-
ский контекст процесса (запускающая 
   другую программу) */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[], 
         char *envp[]){ 

/* Мы будем запускать команду cat c аргументом
   командной строки 03-2.с без изменения 
   параметров среды, т.е. фактически выполнять
   команду "cat 03-2.c", которая должна выдать
   содержимое данного файла на экран. Для 
   функции execle в качестве имени программы 
   мы указываем ее полное имя с путем от 
   корневой директории —/bin/cat. 

   Первое слово в командной строке у нас 
   должно совпадать с именем запускаемой 
   программы. Второе слово в командной строке
   – это имя файла, содержимое которого мы 
   хотим распечатать. */

(void) execle("/bin/cat", "/bin/cat", 
              "03-2.c", 0, envp);

/* Сюда попадаем только при 
   возникновении ошибки */
printf("Error on program start\n");
exit(-1);
return 0;     /* Никогда не выполняется, нужен 
                 для того, чтобы компилятор не
                 выдавал warning */
}
Листинг 3.2. Программа 03-2.с, изменяющая пользовательский контекст процесса

Откомпилируйте ее и запустите на исполнение. Поскольку при нормальной работе будет распечатываться содержимое файла с именем 03-2.c, такой файл при запуске должен присутствовать в текущей директории (проще всего записать исходный текст программы под этим именем). Проанализируйте результат.

Написание, компиляция и запуск программы для изменения пользовательского контекста в порожденном процессе

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

< Лекция 1 || Лекция 2: 1234 || Лекция 3 >
лия логовина
лия логовина

организовать двустороннюю поочередную связь процесса-родителя и процесса-ребенка через pipe, используя для синхронизации сигналы sigusr1 и sigusr2.

Макар Оганесов
Макар Оганесов