שיחת מערכת Linux Exec

Linux Exec System Call



קריאת המערכת exec משמשת לביצוע קובץ השוכן בתהליך פעיל. כאשר קוראים ל- exec קובץ ההפעלה הקודם מוחלף וקובץ חדש מבוצע.

ליתר דיוק, אנו יכולים לומר כי שימוש בשיחת מערכת exec תחליף את הקובץ או התוכנית הישנים מהתהליך בקובץ או תוכנית חדשה. כל תוכן התהליך מוחלף בתוכנית חדשה.







מקטע נתוני המשתמש המבצע את שיחת המערכת exec () מוחלף בקובץ הנתונים ששמו מופיע בארגומנט בעת קריאת exec ().



התוכנית החדשה נטענת לאותו שטח תהליכים. התהליך הנוכחי פשוט הופך לתהליך חדש ומכאן שמזהה התהליך PID אינו משתנה, זאת מכיוון שאיננו יוצרים תהליך חדש אנו רק מחליפים תהליך בתהליך אחר ב- exec.



אם התהליך הפועל כרגע מכיל יותר מחוט אחד אז כל האשכולות יסתיימו ותמונת התהליך החדשה תטען ואז תתבצע. אין פונקציות הורס שמסיימות שרשורים של התהליך הנוכחי.





ה- PID של התהליך אינו משתנה אך הנתונים, הקוד, הערימה, הערימה וכו 'של התהליך משתנים ומוחלפים באלה של התהליך החדש. התהליך החדש מבוצע מנקודת הכניסה.

קריאת מערכת Exec היא אוסף של פונקציות ובשפת התכנות C, השמות הסטנדרטיים של פונקציות אלה הם כדלקמן:



  1. execl
  2. להורג
  3. execlp
  4. execv
  5. להוציא להורג
  6. execvp


יש לציין כאן שלפונקציות אלה יש אותו בסיס מנהל ואחריו אות אחת או יותר. אלה מוסברים להלן:

וגם: זהו מערך של מצביעים המצביעים על משתני סביבה ומועברים במפורש לתהליך הטעון החדש.

ה: l הוא עבור ארגומנטים של שורת הפקודה העביר רשימה לפונקציה

p: p הוא משתנה סביבת הנתיבים שעוזר למצוא את הקובץ שהועבר כארגומנט שיש לטעון לתהליך.

v: v מיועד לארגומנטים של שורת הפקודה. אלה מועברים כמערך של עצות לפונקציה.

מדוע משתמשים ב- exec?

exec משמש כאשר המשתמש רוצה להפעיל קובץ או תוכנית חדשה באותו תהליך.

עבודה פנימית של מנהל

שקול את הנקודות הבאות כדי להבין את פעולתו של מנהל המערכת:

  1. תמונת התהליך הנוכחית מוחלפת בתמונת תהליך חדשה.
  2. תמונת תהליך חדשה היא זו שהעברת כטענת מנהל
  3. התהליך הפועל כעת מסתיים
  4. לתמונת תהליך חדשה יש אותו מזהה תהליך, אותה סביבה ואותו מתאר קובץ (מכיוון שהתהליך אינו מוחלף תמונת התהליך מוחלפת)
  5. נתוני המעבד והזיכרון הווירטואלי מושפעים. מיפוי זיכרון וירטואלי של תמונת התהליך הנוכחית מוחלף בזיכרון וירטואלי של תמונת תהליך חדשה.

תחביר של תפקודי משפחה exec:

להלן התחביר לכל פונקציה של exec:

int execl (const char* path, const char* arg,…)
int execlp (const char* file, const char* arg, ...)
int execle (const char* path, const char* arg,…, char* const envp [])
int execv (const char* path, const char* argv [])
int execvp (קובץ const char*, const char* argv [])
int execvpe (const char* file, 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 . טיעון זה הוא מערך תווים המצביע על מחרוזת סיום null ומגדיר משתנה סביבה.

כדי להשתמש בפונקציות המשפחה exec, עליך לכלול את קובץ הכותרת הבא בתוכנית C שלך:

#לִכלוֹל

דוגמה 1: שימוש בשיחת מערכת exec בתוכנית C

שקול את הדוגמה הבאה בה השתמשנו בשיחות מערכת exec בתכנות C בלינוקס, אובונטו: יש לנו שני קבצי c כאן example.c ו- hello.c:

example.c

קוד:

#לִכלוֹל
#לִכלוֹל
#לִכלוֹל
intרָאשִׁי(intargc, לְהַשְׁחִיר *argv[])
{
printf ('PID של example.c = %d n',חולה());
לְהַשְׁחִיר *טוען[] = {'שלום', 'C', 'תִכנוּת',ריק};
execv('./שלום',טוען);
printf ('חזרה לדוגמא.ג');
לַחֲזוֹר 0;
}

שלום. ג

קוד:

#לִכלוֹל
#לִכלוֹל
#לִכלוֹל
intרָאשִׁי(intargc, לְהַשְׁחִיר *argv[])
{
printf ('אנחנו ב- Hello.c n');
printf ('PID של hello.c = %d n',חולה());
לַחֲזוֹר 0;
}

תְפוּקָה:

PID של example.c = 4733
אנחנו ב- Hello.c
PID של hello.c = 4733

בדוגמה למעלה יש לנו קובץ example.c וקובץ hello.c. בדוגמא .c קובץ קודם כל הדפסנו את מזהה התהליך הנוכחי (קובץ example.c פועל בתהליך הנוכחי). ואז בשורה הבאה יצרנו מערך של רמזים לתווים. הרכיב האחרון של מערך זה צריך להיות NULL כנקודת הסיום.

לאחר מכן השתמשנו בפונקציה execv () שלוקחת את שם הקובץ ואת מערך מצביע התווים כארגומנט שלו. יצוין כאן כי השתמשנו ./ עם שם הקובץ, הוא מציין את נתיב הקובץ. מכיוון שהקובץ נמצא בתיקייה שבה example.c שוכן כך שאין צורך לציין את הנתיב המלא.

כאשר נקראת הפונקציה execv (), תמונת התהליך שלנו תוחלף כעת, דוגמת הקובץ. C אינה בתהליך אך הקובץ hello.c נמצא בתהליך. ניתן לראות שמזהה התהליך זהה בין אם hello.c היא תמונת תהליך או example.c היא תמונת תהליך מכיוון שהתהליך זהה ותמונת התהליך מוחלפת רק.

אז יש לנו עוד דבר לציין כאן שהוא משפט printf () לאחר שה execv () אינו מבוצע. הסיבה לכך היא שהבקרה לעולם לא מוחזרת לתמונת התהליך הישנה לאחר שתמונת תהליך חדשה מחליפה אותה. הפקד חוזר לפונקציית ההתקשרות רק כאשר החלפת תמונת התהליך לא צלחה. (ערך ההחזרה הוא -1 במקרה זה).

ההבדל בין שיחות מערכת fork () ו- exec ():

קריאת המערכת fork () משמשת ליצירת עותק מדויק של תהליך הפעלה והעתק שנוצר הוא תהליך הצאצא ותהליך הריצה הוא תהליך האב. ואילו שיטת מערכת exec () משמשת להחלפת תמונת תהליך בתמונת תהליך חדשה. מכאן שאין מושג של תהליכי הורה וילד בשיחות מערכת exec ().

שיחות מערכת במזלג () מבוצעות בו זמנית התהליכים של ההורה והילד. אך בשיחת מערכת exec (), אם החלפת תמונת התהליך מוצלחת, הפקד אינו חוזר למקום בו נקראה הפונקציה exec אלא היא תבצע את התהליך החדש. הפקד יועבר בחזרה רק אם יש שגיאה.

דוגמה 2: שילוב שיחות מערכת מזלג () ו- exec ()

שקול את הדוגמה הבאה בה השתמשנו גם בשיחות מערכת fork () וגם exec () באותה תוכנית:

example.c

קוד:

#לִכלוֹל
#לִכלוֹל
#לִכלוֹל
intרָאשִׁי(intargc, לְהַשְׁחִיר *argv[])
{
printf ('PID של example.c = %d n',חולה());
pid_t p;
עמ=מזלג();
אם(עמ== -1)
{
printf ('יש שגיאה בעת קריאת fork ()');
}
אם(עמ==0)
{
printf (״אנחנו בתהליך ילדים n');
printf ('קורא hello.c מתהליך הילד n');
לְהַשְׁחִיר *טוען[] = {'שלום', 'C', 'תִכנוּת',ריק};
execv('./שלום',טוען);
}
אַחֵר
{
printf ('אנחנו בתהליך הורים');
}
לַחֲזוֹר 0;
}

hello.c:

קוד:

#לִכלוֹל
#לִכלוֹל
#לִכלוֹל
intרָאשִׁי(intargc, לְהַשְׁחִיר *argv[])
{
printf ('אנחנו ב- Hello.c n');
printf ('PID של hello.c = %d n',חולה());
לַחֲזוֹר 0;
}

תְפוּקָה:

PID של example.c = 4790
אנו נמצאים בתהליך הורים
אנו בתהליך ילדים
התקשר ל- hello.c מתהליך הילד
אנחנו ב- hello.c
PID של hello.c = 4791

בדוגמה זו השתמשנו בשיחת מערכת fork (). כאשר תהליך הילד יוצר 0 יוקצה ל- p ואז נעבור לתהליך הילד. כעת גוש ההצהרות עם אם (p == 0) יבוצע. מוצגת הודעה והשתמשנו בשיחת מערכת execv () ותמונת תהליך הצאצא הנוכחית שהיא example.c תוחלף ב- hello.c. לפני execv () שיחות הילד וההורים היו זהים.

ניתן לראות כי ה- PID של example.c ו- hello.c שונה כעת. הסיבה לכך היא ש- example.c היא תמונת תהליך ההורה ו- hello.c היא תמונת תהליך הילד.