Linux Exec 시스템 호출

Linux Exec System Call



exec 시스템 호출은 활성 프로세스에 있는 파일을 실행하는 데 사용됩니다. exec가 호출되면 이전 실행 파일이 대체되고 새 파일이 실행됩니다.

더 정확하게 말하면 exec 시스템 호출을 사용하면 프로세스의 이전 파일이나 프로그램을 새 파일이나 프로그램으로 대체한다고 말할 수 있습니다. 프로세스의 전체 내용이 새 프로그램으로 대체됩니다.







exec() 시스템 호출을 실행하는 사용자 데이터 세그먼트는 exec() 호출 시 인수에 이름이 제공된 데이터 파일로 대체됩니다.



새 프로그램은 동일한 프로세스 공간에 로드됩니다. 현재 프로세스는 방금 새 프로세스로 바뀌었으므로 프로세스 ID PID는 변경되지 않습니다. 이는 새 프로세스를 생성하지 않기 때문에 exec에서 프로세스를 다른 프로세스로 교체하는 것뿐입니다.



현재 실행 중인 프로세스에 둘 이상의 스레드가 포함되어 있으면 모든 스레드가 종료되고 새 프로세스 이미지가 로드된 다음 실행됩니다. 현재 프로세스의 스레드를 종료하는 소멸자 함수는 없습니다.





프로세스의 PID는 변경되지 않고 프로세스의 데이터, 코드, 스택, 힙 등이 변경되어 새로 로드된 프로세스의 PID로 대체됩니다. 새 프로세스는 진입점에서 실행됩니다.

Exec 시스템 호출은 함수의 모음이며 C 프로그래밍 언어에서 이러한 함수의 표준 이름은 다음과 같습니다.



  1. 실행
  2. 실행하다
  3. 예외
  4. 임원
  5. 집행하다
  6. execvp


여기에서 이러한 기능은 동일한 기반을 갖는다는 점에 유의해야 합니다. 간부 뒤에 하나 이상의 문자가 옵니다. 아래에 설명되어 있습니다.

그리고: 환경 변수를 가리키고 새로 로드된 프로세스에 명시적으로 전달되는 포인터 배열입니다.

NS: l은 함수에 목록을 전달한 명령줄 인수입니다.

NS: p는 프로세스에 로드할 인수로 전달된 파일을 찾는 데 도움이 되는 경로 환경 변수입니다.

V: v는 명령줄 인수입니다. 이들은 함수에 대한 포인터 배열로 전달됩니다.

exec이 사용되는 이유는 무엇입니까?

exec는 사용자가 동일한 프로세스에서 새 파일이나 프로그램을 시작하려고 할 때 사용됩니다.

임원의 내부 작업

exec의 작동을 이해하려면 다음 사항을 고려하십시오.

  1. 현재 프로세스 이미지를 새 프로세스 이미지로 덮어씁니다.
  2. 새 프로세스 이미지는 exec 인수로 전달한 이미지입니다.
  3. 현재 실행 중인 프로세스가 종료됨
  4. 새 프로세스 이미지는 동일한 프로세스 ID, 동일한 환경 및 동일한 파일 디스크립터를 갖습니다(프로세스가 대체되지 않기 때문에 프로세스 이미지가 대체됨).
  5. CPU 통계 및 가상 메모리가 영향을 받습니다. 현재 프로세스 이미지의 가상 메모리 매핑은 새 프로세스 이미지의 가상 메모리로 대체됩니다.

exec 패밀리 함수의 구문:

다음은 exec의 각 기능에 대한 구문입니다.

int execl(const char* 경로, const char* 인수, …)
int execlp(const char* 파일, const char* 인수, …)
int execle(const char* 경로, const char* 인수, …, 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이 반환됩니다. 오류가 발생한 경우 오류 설정됩니다.

구문에서:

  1. 실행할 파일의 전체 경로 이름을 지정하는 데 사용됩니다.
  1. 화난 전달된 인수입니다. 실제로 프로세스에서 실행될 파일의 ​​이름입니다. 대부분의 경우 arg와 path의 값은 동일합니다.
  1. const char* 인수 execl() 함수에서 execlp() 및 execle()은 arg0, arg1, arg2, …, argn으로 간주됩니다. 기본적으로 null로 끝나는 문자열에 대한 포인터 목록입니다. 여기서 첫 번째 인수는 2번 항목에서 설명한 대로 실행될 파일 이름을 가리킵니다.
  1. 환경 환경 변수를 가리키는 포인터를 포함하는 배열입니다.
  1. 파일 새 프로세스 이미지 파일의 경로를 식별할 경로 이름을 지정하는 데 사용됩니다.
  1. 로 끝나는 exec 호출의 기능 그리고 새 프로세스 이미지의 환경을 변경하는 데 사용됩니다. 이 함수는 인수를 사용하여 환경 설정 목록을 전달합니다. 환경 . 이 인수는 null로 끝나는 문자열을 가리키고 환경 변수를 정의하는 문자 배열입니다.

exec 패밀리 함수를 사용하려면 C 프로그램에 다음 헤더 파일을 포함해야 합니다.

#포함하다

예 1: C 프로그램에서 exec 시스템 호출 사용

Linux, Ubuntu의 C 프로그래밍에서 exec 시스템 호출을 사용한 다음 예를 고려하십시오. 여기에 example.c 및 hello.c 두 개의 c 파일이 있습니다.

예.c

암호:

#포함하다
#포함하다
#포함하다
정수기본(정수인수, *argv[])
{
인쇄 ('example.c의 PID = %dN',getpid());
*인수[] = {'안녕하십니까', '씨', '프로그램 작성',없는};
임원('./안녕하십니까',인수);
인쇄 ('example.c로 돌아가기');
반품 0;
}

안녕하세요.c

암호:

#포함하다
#포함하다
#포함하다
정수기본(정수인수, *argv[])
{
인쇄 ('우리는 Hello.c에 있습니다N');
인쇄 ('hello.c의 PID = %dN',getpid());
반품 0;
}

산출:

example.c의 PID = 4733
우리는 Hello.c에 있습니다
hello.c의 PID = 4733

위의 예에는 example.c 파일과 hello.c 파일이 있습니다. 예제 .c 파일에서 먼저 현재 프로세스의 ID를 인쇄했습니다(example.c 파일은 현재 프로세스에서 실행 중입니다). 그런 다음 다음 줄에서 문자 포인터 배열을 만들었습니다. 이 배열의 마지막 요소는 종료 지점으로 NULL이어야 합니다.

그런 다음 파일 이름과 문자 포인터 배열을 인수로 사용하는 execv() 함수를 사용했습니다. 여기에서 파일 이름과 함께 ./를 사용했으며 파일의 경로를 지정한다는 점에 유의해야 합니다. 파일은 example.c가 있는 폴더에 있으므로 전체 경로를 지정할 필요가 없습니다.

execv() 함수가 호출되면 프로세스 이미지가 교체됩니다. 이제 example.c 파일은 프로세스에 없지만 hello.c 파일은 프로세스에 있습니다. 프로세스가 동일하고 프로세스 이미지만 교체되기 때문에 hello.c가 프로세스 이미지이든 example.c가 프로세스 이미지이든 프로세스 ID가 동일함을 알 수 있습니다.

그런 다음 execv()가 실행되지 않은 후 printf() 문을 여기서 주목해야 합니다. 새 프로세스 이미지가 교체되면 제어가 이전 프로세스 이미지로 다시 반환되지 않기 때문입니다. 컨트롤은 프로세스 이미지 교체에 실패한 경우에만 호출 함수로 돌아갑니다. (이 경우 반환 값은 -1입니다).

fork()와 exec() 시스템 호출의 차이점:

fork() 시스템 호출은 실행 중인 프로세스의 정확한 복사본을 만드는 데 사용되며 생성된 복사본은 자식 프로세스이고 실행 중인 프로세스는 부모 프로세스입니다. 반면 exec() 시스템 호출은 프로세스 이미지를 새 프로세스 이미지로 교체하는 데 사용됩니다. 따라서 exec() 시스템 호출에는 부모 및 자식 프로세스의 개념이 없습니다.

fork() 시스템 호출에서는 부모 프로세스와 자식 프로세스가 동시에 실행됩니다. 그러나 exec() 시스템 호출에서 프로세스 이미지 교체가 성공하면 컨트롤은 exec 함수가 호출된 위치로 돌아가지 않고 새 프로세스를 실행합니다. 오류가 있는 경우에만 제어가 다시 전송됩니다.

예제 2: fork() 및 exec() 시스템 호출 결합

동일한 프로그램에서 fork() 및 exec() 시스템 호출을 모두 사용한 다음 예를 고려하십시오.

예.c

암호:

#포함하다
#포함하다
#포함하다
정수기본(정수인수, *argv[])
{
인쇄 ('example.c의 PID = %dN',getpid());
pid_t 피;
NS=포크();
만약(NS== -1)
{
인쇄 ('fork()를 호출하는 동안 오류가 발생했습니다');
}
만약(NS==0)
{
인쇄 ('우리는 자식 프로세스에 있습니다N');
인쇄 ('자식 프로세스에서 hello.c 호출N');
*인수[] = {'안녕하십니까', '씨', '프로그램 작성',없는};
임원('./안녕하십니까',인수);
}
또 다른
{
인쇄 ('우리는 부모 프로세스에 있습니다');
}
반품 0;
}

안녕하세요.c:

암호:

#포함하다
#포함하다
#포함하다
정수기본(정수인수, *argv[])
{
인쇄 ('우리는 Hello.c에 있습니다N');
인쇄 ('hello.c의 PID = %dN',getpid());
반품 0;
}

산출:

example.c의 PID = 4790
우리는 부모 프로세스에 있습니다
우리는 자식 프로세스에 있습니다
자식 프로세스에서 hello.c 호출
우리는 hello.c에 있습니다.
hello.c의 PID = 4791

이 예제에서는 fork() 시스템 호출을 사용했습니다. 자식 프로세스가 생성되면 p에 0이 할당되고 자식 프로세스로 이동합니다. 이제 if(p==0)가 있는 명령문 블록이 실행됩니다. 메시지가 표시되고 execv() 시스템 호출을 사용했으며 example.c인 현재 자식 프로세스 이미지가 hello.c로 바뀝니다. execv() 호출 이전에는 자식 프로세스와 부모 프로세스가 동일했습니다.

이제 example.c와 hello.c의 PID가 다른 것을 알 수 있습니다. example.c가 부모 프로세스 이미지이고 hello.c가 자식 프로세스 이미지이기 때문입니다.