Presentation is loading. Please wait.

Presentation is loading. Please wait.

מערכות הפעלה תרגול 5 – תהליכים ב-Linux (3). מערכות הפעלה - תרגול 52 (c) ארז חדד 2003 תוכן התרגול החלפת הקשר (context switch) ב-Linux יצירת תהליך חדש ב-Linux.

Similar presentations


Presentation on theme: "מערכות הפעלה תרגול 5 – תהליכים ב-Linux (3). מערכות הפעלה - תרגול 52 (c) ארז חדד 2003 תוכן התרגול החלפת הקשר (context switch) ב-Linux יצירת תהליך חדש ב-Linux."— Presentation transcript:

1 מערכות הפעלה תרגול 5 – תהליכים ב-Linux (3)

2 מערכות הפעלה - תרגול 52 (c) ארז חדד 2003 תוכן התרגול החלפת הקשר (context switch) ב-Linux יצירת תהליך חדש ב-Linux סיום ביצוע תהליך ב-Linux

3 מערכות הפעלה - תרגול 53 (c) ארז חדד 2003 החלפת הקשר ב-Linux (1) מעבד מריץ מספר תהליכים "בו-זמנית"  המעבד מריץ תהליך אחד לפרק זמן כלשהו ואז משעה את ביצועו ועובר להמשיך להריץ תהליך אחר – "מיתוג" בין התהליכים המתבצעים לכל תהליך יש "הקשר ביצוע" (execution context) המכיל את כל המידע הדרוש לביצוע התהליך  מחסניות, רגיסטרים, דגלים, תכולת זיכרון, קבצים פתוחים פעולת המיתוג שומרת את הקשר התהליך הנוכחי וטוענת למעבד את הקשר הביצוע של התהליך הבא  הקשר התהליך הנוכחי מתחלף – מכאן שם הפעולה "החלפת הקשר"

4 מערכות הפעלה - תרגול 54 (c) ארז חדד 2003 החלפת הקשר ב-Linux (2) הפונקציה היחידה המפעילה את החלפת ההקשר היא הפונקציה schedule(). קוד הרוצה לגרום להחלפת הקשר קורא לפונקציה זו בלבד הפונקציה schedule() בוחרת מי יהיה התהליך הבא לזימון למעבד, כפי שראינו בתרגול הקודם, ואז קוראת לפונקציה בשם context_switch() המבצעת את החלפת ההקשר כזכור מתרגול קודם, schedule() והחלפת ההקשר מתבצעים בפסיקות חסומות על-מנת למנוע הפעלה רקורסיבית של הזמן והחלפת ההקשר, דבר העלול לגרום לשיבוש פעולת מערכת ההפעלה החלפת הקשר היא בקירוב רצף הביצוע הבא: 1. שמירת נתוני הקשר התהליך הנוכחי 2. מעבר למחסנית הגרעין של התהליך הבא (שהופך להיות התהליך הנוכחי החדש) 3. טעינת נתוני הקשר התהליך הנוכחי החדש 4. קפיצה לכתובת הבאה לביצוע של התהליך הנוכחי החדש

5 מערכות הפעלה - תרגול 55 (c) ארז חדד 2003 החלפת הקשר ב-Linux (3) מרבית ההקשר של תהליך ב-Linux מאוחסן במתאר התהליך ולכן אין צורך "לשמור" ו"לטעון" אותו מחדש בכל החלפת הקשר  נשמרים ונטענים בעיקר הרגיסטרים והדגלים  השמירה והטעינה – במחסנית הגרעין של התהליך ובמתאר התהליך בשדה thread פעולת החלפת ההקשר כוללת גם החלפת איזורי הזיכרון אליהם המעבד ניגש ב-User Mode: מאילו של התהליך הנוכחי לאילו של התהליך הבא  עם זאת, פעולת החלפת ההקשר מתבצעת באיזור הזיכרון של הגרעין, שאינו מתחלף  במהלך החלפת הקשר לא משנים את ערכי הרגיסטרים של הסגמנטים (cs, ds, ss, es), למרות שאיזור הזיכרון של התהליך אכן מוחלף. הסבר בתרגול על הזיכרון הוירטואלי

6 מערכות הפעלה - תרגול 56 (c) ארז חדד 2003 Task State Segment (1) לכל מעבד ב-Linux יש איזור זיכרון בגרעין המכיל מידע מתוך הקשר התהליך הנוכחי המתבצע באותו מעבד איזור זה קרוי Task State Segment – TSS קיומו של איזור זה הוא אילוץ של החומרה (IA32)  המעבד קורא את כתובת מחסנית הגרעין של התהליך הנוכחי משדה ב-TSS בעת מעבר ל-Kernel Mode  ה-TSS משמש בחומרה לפעולות נוספות כגון בקרת גישה בפעולות I/O ה-TSS של כל המעבדים מוכלים במערך init_tss בעת ביצוע החלפת הקשר, מעדכנים שדות ב-TSS החלפת הקשר ב-Linux

7 מערכות הפעלה - תרגול 57 (c) ארז חדד 2003 Task State Segment (2) ההגדרות נמצאות בקובץ הגרעין include/asm/processor.h struct tss_struct {.. unsigned long esp0;.. }; struct tss_struct init_tss[NR_CPUS]; מצביע לבסיס מחסנית הגרעין של התהליך הנוכחי במעבד (ערך esp בכניסה ל-kernel mode) החלפת הקשר ב-Linux

8 מערכות הפעלה - תרגול 58 (c) ארז חדד 2003 שדה thread במתאר התהליך שדה זה משמש לשמירת חלק מהקשר התהליך שדה זה הוא מסוג thread_struct המוגדר בקובץ הגרעין include/asm/processor.h: struct thread_struct { unsigned long esp0; unsigned long eip; unsigned long esp; unsigned long fs; unsigned long gs;.. union i387_union i387;.. }; מצביע לכתובת הבסיס של מחסנית הגרעין של התהליך מאחסן את המצביע לכתובת הבאה לביצוע לאחר החלפת הקשר מאחסן את המצביע לראש המחסנית (בגרעין) בהחלפת הקשר מאחסן את רגיסטרי הסגמנטים fs ו-gs מאחסן את הרגיסטרים של היחידה המתימטית החלפת הקשר ב-Linux

9 מערכות הפעלה - תרגול 59 (c) ארז חדד 2003 הפונקציה context_switch() הפונקציה המבצעת את החלפת ההקשר נקראת context_switch()  קובץ גרעין kernel/sched.c  פונקציה זו מבצעת את החלפת איזורי הזיכרון ואז קוראת למאקרו switch_to המבצע את פעולות הטעינה והשמירה  הפונקציה context_switch() היא חלק מאלגוריתם הזימון החדש. בגרסה הסטנדרטית של הגרעין 2.4.X קיים רק switch_to inline task_t *context_switch(task_t *prev, task_t *next) {..קוד החלפת איזורי הזיכרון switch_to(prev, next, prev); return prev; } החלפת הקשר ב-Linux

10 מערכות הפעלה - תרגול 510 (c) ארז חדד 2003 המאקרו switch_to (1) המאקרו מוגדר בקובץ הגרעין include/asm/system.h הקריאה למאקרו: switch_to(prev, next, last)  prev מצביע למתאר התהליך הנוכחי, שמוותר על המעבד  next מצביע למתאר התהליך הבא, שמקבל את המעבד  last הוא פרמטר שכבר אינו בשימוש באלגוריתם הזימון החדש. בגרסת 2.4.X הסטנדרטית, פרמטר זה מצביע לאחר החזרה מ-switch_to על מתאר התהליך ממנו בוצע switch_to אל התהליך הנוכחי movl prev, %eax movl next, %edx pushl %esi pushl %edi pushl %ebp הקומפיילר (gcc) מניח שרגיסטרים אלו אינם משתנים עד סוף switch_to ולכן יש לשמור אותם ולשחזר אותם בהמשך הרצת התהליך החלפת הקשר ב-Linux

11 מערכות הפעלה - תרגול 511 (c) ארז חדד 2003 המאקרו switch_to (2) movl %esp, prev->thread.esp movl next->thread.esp, %esp movl $1f, prev->thread.eip pushl next->thread.eip jmp __switch_to 1: popl %ebp popl %edi popl %esi החלפת מחסניות הגרעין מזו של prev לזו של next – זו למעשה נקודת החלפת ההקשר התהליך prev ימשיך מהכתובת של התוית "1" כשיחזור לרוץ התהליך next ימשיך לרוץ מכתובת זו בסיום __switch_to שחזור הרגיסטרים ממחסנית הגרעין של next לפני סיום switch_to קפיצה לפונקציה __switch_to החלפת הקשר ב-Linux

12 מערכות הפעלה - תרגול 512 (c) ארז חדד 2003 הפונקציה __switch_to() (1) פונקציה זו משלימה את רצף הפעולות במסגרת החלפת ההקשר  קובץ גרעין arch/i386/kernel/process.c הפונקציה מוגדרת באופן מיוחד: void FASTCALL(__switch_to(struct task_struct *prev_p, struct task_struct *next_p)); ההגדרה FASTCALL פירושה שהפונקציה מקבלת פרמטרים ברגיסטרים ולא במחסנית  הגדרה ייחודית ל-GCC: #define FASTCALL __attribute__(regparm(3))  עד 3 פרמטרים מועברים ברגיסטרים eax, edx, ecx (משמאל לימין) לכן, prev_p מועבר בתוך eax ו-next_p בתוך edx החלפת הקשר ב-Linux

13 מערכות הפעלה - תרגול 513 (c) ארז חדד 2003 הפונקציה __switch_to() (2) פונקציה זו מופעלת באמצעות קפיצה מתוך המאקרו switch_to (למעשה, מתוך הפונקציה context_switch()) כאשר הפרמטרים כבר ברגיסטרים jmp __switch_to מכיוון ש-__switch_to() מוגדרת כפונקציה, הקוד שלה מסתיים בפקודת ret ששולפת כתובת חזרה מהמחסנית וקופצת אליה  המחסנית היא מחסנית הגרעין של התהליך הנוכחי החדש  כתובת החזרה היא next->thread.eip כפי שהוכנסה בקוד של המאקרו switch_to. ברוב המקרים, זוהי כתובת התוית '1' של המשך ביצוע המאקרו switch_to בתוך הפונקציה context_switch() אם next הוא תהליך שרץ פעם ראשונה, הכתובת היא אחרת כפי שנראה בהמשך החלפת הקשר ב-Linux

14 מערכות הפעלה - תרגול 514 (c) ארז חדד 2003 הפונקציה __switch_to() (3) struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; struct tss_struct *tss = init_tss + smp_processor_id(); unlazy_fpu(prev_p); tss->esp0 = next->esp0;.. movl %fs, prev->fs movl %gs, prev->gs if (prev->fs | prev->gs | next->fs | next->gs) {.. movl next->fs, %fs movl next->gs, %gs.. } /* load debug registers */ /* load IO permission bitmap */ return; שמירה ושחזור של fs ו-gs שמירה ושחזור של הרגיסטרים של היחידה המתימטית עדכון מצביע מחסנית הגרעין של התהליך הנוכחי ב-TSS החלפת הקשר ב-Linux

15 (c) ארז חדד 2003מערכות הפעלה - תרגול 515 context_switch: …… switch_to: movl $1f, prev->thread.eip $1f prev pushl next->thread.eip next task_struct esp מחסנית הגרעין של התהליך next 1: switch_to:__ ret eip המשך הביצוע של next ……… task_struct $1f thread.eip thread.esp מחסנית הגרעין של התהליך prev $1f ebp edi esi מסגרת של context_switch() $1f ebp edi esi מסגרת של context_switch() ebp edi esi מסגרת של context_switch()

16 מערכות הפעלה - תרגול 516 (c) ארז חדד 2003 שמירת ערכי הרגיסטרים (1) מרבית הרגיסטרים שבהם התהליך משתמש ב-User Mode נשמרים במעבר ל-Kernel Mode (ראינו דוגמה חלקית בתרגול 2)  המצביע למחסנית הרגילה ss:esp נשמר ע"י החומרה במחסנית הגרעין מייד עם תחילת המעבר ל-kernel mode  eflags נשמר באופן אוטומטי במחסנית הגרעין ואחריו כתובת החזרה (cs:eip) בעת הקפיצה לטיפול בפסיקה  es, ds, eax, ebp, edi, esi, edx, ecx, ebx נשמרים במחסנית הגרעין דרך SAVE_ALL בתחילת שגרת הטיפול בפסיקה החלפת הקשר ב-Linux

17 מערכות הפעלה - תרגול 517 (c) ארז חדד 2003 שמירת ערכי הרגיסטרים (2) ומה לגבי שמירת הקשר הביצוע בתוך הגרעין?  המאקרו switch_to אינו משפיע מבחינת ערכי רגיסטרים על context_switch(), משום שהוא מופעל ממש לפני החזרה מהפונקציה  בין הפונקציה schedule() לפונקציה context_switch() מתקיימים יחסי caller-callee (פונקציה קוראת / פונקציה נקראת, כפי שראינו בתרגול 2), לכן בפונקציה schedule() לא מניחים שערכי הרגיסטרים פרט ל-ebx, ebp, esi, edi משתמרים  ebp, esi, edi נשמרים במחסנית במאקרו switch_to ב-schedule() וב-context_switch(), ערך ebx מלפני הקריאה ל-switch_to אינו בשימוש לאחר הקריאה  esp ו-eip נשמרים בתוך מתאר התהליך לפני ביצוע החלפת ההקשר במאקרו switch_to  הרגיסטרים של הסגמנטים אינם משתנים בהחלפת הקשר ולכן אינם נשמרים למעט fs ו-gs, שלפעמים נמצאים בשימוש מיוחד ע"י תהליכים ולכן נשמרים החלפת הקשר ב-Linux

18 מערכות הפעלה - תרגול 518 (c) ארז חדד 2003 יצירת תהליך חדש ב-Linux (1) קריאות המערכת המשמשות ליצירת תהליכים חדשים (כדוגמת fork()) משתמשות בפונקציה פנימית של הגרעין הקרויה do_fork() לבניית ההקשר של התהליך החדש  קובץ גרעין kernel/fork.c הפונקציה do_fork() מעתיקה את מרבית הנתונים ממתאר תהליך האב למתאר חדש של תהליך הבן שהיא יוצרת  קבצים פתוחים (file descriptors), בעלות משותפת על משאבי מערכת  העתקת תכולת הזיכרון מתבצעת בשיטה מיוחדת – פרטים בתרגולים הבאים

19 מערכות הפעלה - תרגול 519 (c) ארז חדד 2003 יצירת תהליך חדש ב-Linux (2) הפונקציה do_fork() בונה מחסנית גרעין לתהליך הבן ע"י קריאה לפונקציה copy_thread() מתאר תהליך הבן מקושר לרשימת התהליכים ו"בני משפחתו" ע"י המאקרו SET_LINKS הקישור בין ה-pid של תהליך הבן למתאר תהליך הבן מופעל ע"י קריאה ל-hash_pid() תהליך הבן מועבר למצב TASK_RUNNING ומוכנס ל- runqueue ע"י קריאה ל-wake_up_process() לסיום, הפונקציה do_fork() מחזירה את ה-pid של תהליך הבן, וערך זה מוחזר לבסוף לתהליך האב

20 מערכות הפעלה - תרגול 520 (c) ארז חדד 2003 הפונקציה copy_thread() (1) פונקציה זו (קובץ גרעין arch/i386/kernel/process.c) מאתחלת את תכולת מחסנית הגרעין של תהליך הבן ואת שדה thread במתאר תהליך הבן. להלן תיאור של עיקר הקוד  p מצביע למתאר תהליך הבן  regs מצביע לרגיסטרים שאוחסנו במחסנית הגרעין של האב באמצעות הקפיצה לפסיקה ו- SAVE_ALL במהלך המעבר ל-kernel mode  struct pt_regs הוא רשומה המכילה את ערכי הרגיסטרים בדיוק בסדר בו הם מאוחסנים במחסנית באמצעות הקפיצה לפסיקה ו- SAVE_ALL struct pt_regs childregs; child_regs מצביע על תחילת המקום בו מאוחסנים הרגיסטרים במחסנית childregs = ((struct pt_regs *)(8192 + (unsigned long) p)) – 1; העתקת הרגיסטרים ממחסנית הגרעין של האב למחסנית הגרעין של הבן struct_cpy(childregs, regs); כזכור מתרגול 2, לתהליך הבן מוחזר ערך 0 מביצוע fork() childregs->eax = 0; יצירת תהליך חדש ב-Linux

21 מערכות הפעלה - תרגול 521 (c) ארז חדד 2003 הפונקציה copy_thread() (2) p->thread.esp צריך להצביע על ראש מחסנית הגרעין בתחילת הביצוע p->thread.esp = (unsigned long) childregs; p->thread.esp0 צריך להצביע על בסיס מחסנית הגרעין p->thread.esp0 = (unsigned long) (childregs + 1); בתחילת הביצוע תהליך הבן יריץ את ret_from_fork p->thread.eip = (unsigned long) ret_from_fork; /* save fs and gs registers in thread field */ /* copy saved math regs in thread field from father to son */

22 מערכות הפעלה - תרגול 522 (c) ארז חדד 2003 הפונקציה ret_from_fork() פונקציה זו מופעלת כאשר תהליך הבן מזומן לראשונה למעבד לאחר החלפת הקשר הפונקציה מוגדרת בקובץ הגרעין arch/i386/kernel/entry.S ret_from_fork:.. jmp ret_from_syscall כפי שראינו בתרגול 2, ביצוע ret_from_syscall ייגרום לתהליך הבן לחזור ל-user mode לאחר שנשלפו כל הרגיסטרים מהמחסנית למעשה, ביצוע הקוד ב-ret_from_fork ייגרום לסיום הקריאה fork() בתהליך הבן עם ערך מוחזר 0

23 מערכות הפעלה - תרגול 523 (c) ארז חדד 2003 ss esp eflags cs eip orig_eax es ds eax=0 ebp edi esi edx ecx ebx נשמר על ידיSAVE_ALL ערך eax נשמר בכל תחילת טיפול בפסיקה נשמר על ידי הקפיצה לפסיקה מצביע למחסנית התהליך ב- user mode...... ret_from_fork...... struct pt_regs task_struct thread.esp0 thread.eip thread.esp p

24 מערכות הפעלה - תרגול 524 (c) ארז חדד 2003 סיום ביצוע תהליך (1) תהליך מסיים את ביצוע הקוד ע"י קריאת המערכת exit() אם קוד התהליך לא קורא במפורש ל-exit(), מתבצעת קריאה אוטומטית ל-exit() לאחר שהפונקציה main() חוזרת, מתוך הספריה libc  מתוך פונקצית הספריה __libc_start_main() שקוראת ל- main() בתחילת ביצוע התכנית ביצוע קוד תהליך יכול גם להיקטע בעקבות אירועים נוספים  תקלה לא מטופלת במהלך ביצוע הקוד, כגון גישה לא חוקית לזיכרון או חלוקה ב-0  הריגת תהליך אחד על-ידי תהליך אחר

25 מערכות הפעלה - תרגול 525 (c) ארז חדד 2003 סיום ביצוע תהליך (2) הפונקציה do_exit() מופעלת בכל מקרה של סיום ביצוע התהליך  קובץ גרעין kernel/exit.c בין השאר, פונקציה זו מבצעת את הפעולות הבאות:  משחררת את המשאבים שבשימוש התהליך  מעדכנת שדה exit_code במתאר התהליך להכיל את הערך המוחזר ע"י exit()  מעדכנת קשרי משפחה: כל בניו של התהליך שסיים הופכים להיות בנים של init  מעבירה את מצב התהליך ל-TASK_ZOMBIE  קוראת ל-schedule(), שמוציאה את התהליך מה-runqueue ומזמנת תהליך אחר לביצוע במעבד. ביצוע התהליך מסתיים סופית בביצוע switch_to

26 מערכות הפעלה - תרגול 526 (c) ארז חדד 2003 סיום ביצוע תהליך (3) מתאר התהליך מפונה רק כאשר תהליך האב מקבל חיווי על סיום התהליך, באמצעות קריאה כדוגמת wait() פינוי מתאר התהליך מבוצע ע"י הפונקציה release_task()  קובץ גרעין kernel/exit.c פונקציה זו, בין השאר, מנתקת את התהליך מרשימת התהליכים (REMOVE_LINKS) וממנגנון הקישור ל-pid (unhash_pid()), ומפנה את השטח המוקצה למתאר התהליך ומחסנית הגרעין


Download ppt "מערכות הפעלה תרגול 5 – תהליכים ב-Linux (3). מערכות הפעלה - תרגול 52 (c) ארז חדד 2003 תוכן התרגול החלפת הקשר (context switch) ב-Linux יצירת תהליך חדש ב-Linux."

Similar presentations


Ads by Google