Exec (системийн дуудалт)

Системийн дуудлага гүйцэтгэгч гэр бүл

Системийн дуудлагын гэр бүл нь процессоор гүйцэтгэгдэж байгаа програмыг орлуулдаг. Үйл явцыг дуудах үед процессын бүх код (текст) болон өгөгдөл алдагдаж, шинэ програмын ажиллагааг гүйцэтгэх болно. Хэдийгээр бүх өгөгдөл солигдсон боловч бүх нээлттэй файлын тодорхойлогчууд нь гүйцэтгэхийг шууд зааж өгөхгүй бол дуудлага хийсний дараа нээлттэй байна. Доорх диаграммд процесс ажиллаж байгаа Хөтөлбөр 1. Хөтөлбөрийн 2-р процессоор гүйцэтгэгдэж буй програмыг орлуулахын тулд програмыг дуудна.

exec()

execlp

Execlp системийн дуудлага нь тодорхой файлын нэр нь slash (/) тэмдэгт агуулаагүй бол ажиллуулах боломжтой файлыг хайж байгаа бүрхүүлийн үйлдлүүд давхардсан. Хайлтын зам нь хүрээллээр PATH хувьсагчаар тодорхойлогдсон зам юм. Хэрэв энэ хувьсагч тодорхойлогдоогүй бол ": / bin: / usr / bin" анхдагч замыг ашигладаг.

Шинэ програмд нэмэлт өгөгдлүүдийн тоо эмхэтгэх үед мэдэгдэж байгаа үед execlp системийн дуудлагыг ашиглаж болно. Хэрэв аргументуудын тоо эмхэтгэх цагт мэдэгддэггүй бол execvp тушаалыг ашиглах хэрэгтэй.

#include <unistd.h>

int execlp(const char *file, const char *arg, ...);

Үлдсэн аргументууд

Const char * arg ба дараачийн эллипсүүд нь arg0, arg1, ..., argn гэж тооцогддог. Хамтдаа тэд нэгтгэсэн хөтөлбөрт боломжтой нэмэлт өгөгдлүүдийг харуулсан null-terminated мөрүүдэд нэг буюу хэд хэдэн заагч жагсаалтыг хамт тайлбарлана. Эхний аргумент нь конвенцоор гүйцэтгэгдэж байгаа файлтай холбоотой файлын нэрийг зааж өгөх ёстой. Аргументуудын жагсаалтыг NULL заагчийн тусламжтайгаар цуцална.

Жишээ нь

Модуль-2 / examples / src / execlp_ls.c нь execv-ийг хэрхэн ашиглаж болохыг харуулах дараах жишээг олж чаддаг.

#include <unistd.h> // execlp()
#include <stdio.h>  // perror()
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE

int main(void) {
  execlp("ls", "ls", "-l", NULL);
  perror("Return from execlp() not expected");
  exit(EXIT_FAILURE);
}

Програм нь execlp -г ашигладаг бөгөөд ls нэртэй гүйцэтгэгддэг файлын хувьд PATH-ийг хайж олохын тулд шинэ програмд нэмэлт өгөгдөл өгдөг. Шинэ програм нь бүрхүүлийн тушаал ls-д ашигладаг ижил програм юм.

execvp

Хэрэв тодорхойлогдсон файлын нэр нь slash (/) тэмдэгт агуулаагүй бол execvp системийн дуудлага нь ажиллуулах боломжтой файлыг хайж олох болно. Хайлтын зам нь хүрээллээр PATH хувьсагчаар тодорхойлогдсон зам юм. Хэрэв энэ хувьсагч тодорхойлогдоогүй бол ": / bin: / usr / bin" анхдагч замыг ашигладаг. Үүнээс гадна зарим алдааг тусгайлан авч үздэг.

#include <unistd.h>

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

argv

Ардчилсан вектор. Нэмэлт аргументууд нь шинэ хөтөлбөрт багтсан нэмэлт өгөгдлүүдийн жагсаалтыг илэрхийлдэг. Эхний аргумент нь конвенцоор гүйцэтгэгдэж байгаа файлтай холбоотой файлын нэрийг зааж өгөх ёстой. Чиглэгчийн массив нь NULL заагчаар дуусгавар болно.

Жишээ нь

Модуль-2 / examples / src / execvp_ls.c та execvp-г хэрхэн ашиглаж болохыг харуулах дараах жишээ програмыг олно.

#include <unistd.h> // execvp()
#include <stdio.h>  // perror()
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE

int main(void) {
  char *const cmd[] = {"ls", "-l", NULL};
  execvp(cmd[0], cmd);
  perror("Return from execvp() not expected");
  exit(EXIT_FAILURE);
}

Програм нь execvp-г ls тушаалаар гүйцэтгэгдэж болох файл болгож PATH -г хайж, шинэ програмд нэмэлт өгөгдөл болгон өгч байна. Шинэ програм нь бүрхүүлийн тушаал ls-д ашигладаг ижил програм юм. Execvp-ыг ашиглахтай харьцуулахад бид execvp-ийг ашиглах үед л ls-д зориулсан бүрэн замыг өгөх шаардлагагүй юм.

execv

Execvp -тэй харьцуулахад execv системийн дуудлага PATH-ийг хайдаггүй. Үүний оронд шинэ гүйцэтгэгдэж байгаа бүх замыг зааж өгөх ёстой.

#include <unistd.h>

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

argv

Ардчилсан вектор. Аргумент аргумент нь null-terminated тэмдэгт мөрүүдэд тэмдэгт чиглүүлэгч массив юм. Энэ массын хамгийн сүүлийн гишүүн нь null заагч байна. Эдгээр мөрүүд нь шинэ процессийн дүрслэлд байгаа нэмэлт өгүүллийн жагсаалтыг бүрдүүлнэ. Argv [0] нь шинэ program.d-д гүйцэтгэгдэж байгаа файлын нэрийг зааж өгөх ёстой.

Жишээ нь

Module-2 / examples / src / execv_ls.c нь execv-ийг хэрхэн ашиглаж болохыг харуулсан дараах жишээ файлыг олно.

#include <unistd.h> // execv()
#include <stdio.h>  // perror()
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE

int main() {
  char *const argv[] = {"/bin/ls", "-l", NULL};
  execv(argv[0], argv);
  perror("Return from execv() not expected");
  exit(EXIT_FAILURE);
}


Энэ тохиолдолд шийдэл нь exec () системийн дуудлагыг ашиглах явдал юм. Үнэндээ exec () дуудлагын хэд хэдэн янзын амт байдаг боловч бүгд үндсэндээ ижил үүрэг гүйцэтгэдэг. Exec () системийн дуудлага нь Линукс дээр гүйцэтгэгдсэн програмыг авах цорын ганц арга зам юм. Үүнийг гүйцэтгэх арга нь хэрэглэгчийн () дуудах параметр байдлаар нэрлэгдсэн програмын файлд агуулагдсан текст ба хэрэглэгчийн өгөгдөлтэй гүйцэтгэгч () дуудлагыг гүйцэтгэх үйл явцын текст болон хэрэглэгчийн өгөгдлийн сегментийг солих явдал юм. Энэ нь энгийн жишээн дээр хамгийн сайн тайлбарласан байж болох юм.

Үүнийг хийхийн өмнө би гүйцэтгэх () талаар арай илүү тайлбарлахын тулд бага зэрэг засах хэрэгтэй болно. Бүрхүүлээс програмыг ажиллуулахдаа параметрийг тодорхойлж, програмыг командын мөрөнд оруулан зааж өгч болно. C талаархи таны мэдлэгээс харахад эдгээр тушаалын мөрний утгыг main () аргумент болон арваалах параметрүүдийн тусламжтайгаар програмд ​​зориулж гаргасан болохыг мэддэг. Ямар ч гэсэн бүрхүүл нь тушаалын мөрийн утгыг авч тэдгээрийг аргумент болон арбитрын хувьд таны өмнөөс ажиллуулж байгаа програмуудад дамжуулж чаддаг байх ёстой. Энэ тушаалыг тушаалын мөрийн утгыг exec () -д тохирох хэлбэрээр илгээж гүйцэтгэх бөгөөд энэ нь аргумент болон argv маягаар харагдах болно гэсэн шинэ програмыг ажиллуулах болно.

Эдгээрийг харуулах тушаалын хамгийн хялбар хувилбар нь execl () гэж нэрлэгддэг. Энэ загварын загвар нь:

#inciude <unistd.h>

	int execl(char *patbname, char *arg0, ...);

Замын нэр нь гүйцэтгэх тушаалын бүрэн зам юм. Үүний дараа тэмдэглэгээний тэмдэгт мөр рүү зааж буй хувьсагчийн урт жагсаалт. Эдгээр нь шинэ програмд argv сануулагдсан массивын агуулга болно. Execl () дахь заавруудын жагсаалтыг NULL заагчийн тусламжтайгаар цуцална. Дараах жишээ програм нь ls -l тушаалыг ажиллуулахын тулд execl ():

#inciude <stdio.h>


	main()
	{
		execl("/bin/ls", "ls", "-l", 0); 
		printf("Can only get here on error\n");
	}

Энэ жишээн дээр execl () -ийн эхний параметр нь ls тушаалын бүтэн замыг хэлнэ. Энэ нь файлын агуулга дээр ажиллаж байгаа файлыг агуулах файл юм. Үлдсэн execl () параметрүүд нь шинэ програмд ​​argv массив элемент зааж өгч буй мөрүүдийг агуулна. Энэ жишээн дээр ls програм нь ls тушаалаар argv [0] -г зааж, string -l нь argv [1] -г заадаг гэсэн үг юм.

Ердийн үед exec () дуудлагууд буцаж ирэхгүй. Ер нь, тэдгээр нь функц нь өөр програмд ​​дууддаг текст болон хэрэглэгчийн өгөгдлийн сегментүүдийг солих явдал юм. Ингэснээр тэд буцаж юу ч байхгүй болно!

Гүйцэтгэгч () нь ямар ч шалтгаанаар амжилтгүй дууддаг (ихэвчлэн та үүнийг ажиллуулах эрх байхгүй учраас) алдаатай холбоотой ямар нэг зүйлийг хийх боломжтой болохын тулд буцаж ирнэ.

Эдгээр бүх параметрүүдийг шинэ програмд ​​ашиглахаас гадна гүйцэтгэгчийн хувьд () дуудах хувьсагчийн утгыг дамжуулдаг:

extern char **environ;

Энэ хувьсагч нь argv хувьсагчтай ижил форматтай байдаг бөгөөд байгаль орчинд дамжуулагдах зүйлс нь тушаалын мөрийн параметрийн оронд процессийн орчинд (экспортлогдсон бүх бүрхүүлийн хувьсагчийн утга гэх мэт) утгууд юм. Execl () тохиолдолд шинэ програмын орчны хувьсагчийн утга нь дуудлага хийх явцад энэ хувьсагчийн утгын хуулбар болно.

Execl () exec () нь өмнөх жишээн дээрхтэй адил бүх параметрүүдийг жагсааж болохуйц нарийн нөхцөлд байна. Одоо та ls-ийг ажиллуулахгүй програмыг бичихийг хүсэж байгаа боловч хүссэн ямар ч програмыг ажиллуулж тушаалын мөрийн параметрүүдийг хэд хэдэн тоогоор дамжуулж өнгөрүүлээрэй. Мэдээжээр execl () нь энэ ажлыг хийхгүй.

Энэ шаардлагыг биелүүлдэг доорх жишээ програм нь execv () ажиллахаар гүйцэтгэгдэнэ () нь доор дурдсаныг гүйцэтгэхийг харуулж байна:

#inciude <stdio.h>

	main(int argc, char **argv)
	{
		if (argc==1)
		{
			printf("Usage: run <command> [<paraneters>]\n"); 
			exit(1)
		}
		execv(argv[l], &argv[1)); 
		printf("Sorry...   couldn't run that!\n");
	}

Execv () -ийн загвар нь зөвхөн хоёр параметр авдаг бөгөөд эхнийх нь тушаалын ажиллах бүрэн бүтэн зам бөгөөд хоёр дахь нь шинэ програм руу нэвтрэх аргvний утга юм. Өмнөх жишээн дээр энэ утгыг run тушаалаар дамжуулсан argv утгаас гаргасан бөгөөд run тушаал нь таны дамжуулж байгаа тушаалын мөрийн параметрийн утгуудыг авч дамжуулдаг.

Тушаалын тушаал ашиглан тушаалын дарааллаар дараах тушаал байна:

$ run ls -l mtos
	Sorry... couldn't run that!
	$ run /bin/ls -l mtos total 2
	drwxr-xr-x	2 pc	book	1024 Apr  2 20:11 tdd
	drwxr-xr-x	2 pc	book	1024 Apr  2 20:11 tsh

Эхний оролдлого амжилтгүй болохыг ажиглаарай, энэ нь та execv () (эсвэл execl ()) ашиглаж байгаа үед ажиллуулахыг хүсч байгаа тушаал дээр full pathuame-г зааж өгөх хэрэгтэй бөгөөд хоёр дахь оролдлогийн үр дүнгээс харж болно .

Энд байгаа асуудал бол гүйцэтгэгчийн гүйцэтгэх хоёр () гэсэн хувилбарууд нь таны зааж өгсөн тушаалыг хайхдаа таны PATH орчны хувьсагч дахь утгуудыг ашиглахгүй байх явдал юм. Гэхдээ та таамаглаж байсанчлан exec () тушаалуудын хувилбарууд байдаг. Эдгээрийг execlp () болон execvp () гэж нэрлэдэг бөгөөд энэ нь эхний хостой яг адилхан боловч шаардлагатай тушаалыг олохын тулд PATH утгыг бас ашигладаг.

Гүйцэтгэгчийн сүүлийн хоёр хувилбарууд нь эхний хоёртай (өөрөөр хэлбэл тэд PATH ашигладаггүй) адил боловч автоматаар анхдагч хүлээн авахын оронд шинэ програмд орчны утгыг гараар зааж өгдөг. Тэдгээр нь execle () болон execve () гэж нэрлэгддэг. Дараах нь зургаан exec () хувилбарууд болон тэдгээрийн параметрийн дугаар, төрлүүдийн жагсаалт юм:

int execl(pathname, argo, ..., argn, 0); 
	int execv(pathname, argv);
	int execlp(cmdname, arg0, ..., argn, 0); 
	int execvp(cmdname, argv);
	int execle(patbname, arg0, ..., arga, 0, envp);
	int execve(pathname, argv, envp);

	char *pathname, *cmdname;
	char *arg0, ..., *argn;
	char **argv, **envp;

Үнэн чанартаа, аль ч процессоор бичигдсэн аль ч талбарыг хуулж авахын тулд процессууд хоёулаа тэдгээрийн хуулбаруудтай байх ёстой. Хэрвээ хүүхэд процессийг даруй гүйцэтгэх () дуудлагыг гүйцэтгэх юм бол, хуваалцсан өгөгдлийн сегментийн зайг ажиллуулах () гүйцэтгэхээс өмнө хуулагдах болно.