Presentation is loading. Please wait.

Presentation is loading. Please wait.

מערכות הפעלה תרגול 4 – החלפת הקשר (context switch)

Similar presentations


Presentation on theme: "מערכות הפעלה תרגול 4 – החלפת הקשר (context switch)"— Presentation transcript:

1 מערכות הפעלה תרגול 4 – החלפת הקשר (context switch)

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

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

4 מערכות הפעלה - תרגול 44 (c) ארז חדד 2003 החלפת הקשר ב-Linux ב Linux לא ניתן לבצע החלפת הקשר כפויה לתהליך שנמצא ב-kernel mode. אם בעקבות פסיקה נוצר צורך לבצע החלפת הקשר, היא תתבצע לאחר שהתהליך יסיים את הפעולה בkernel- mode, לפני חזרתו ל-user mode. בגלל שהkernel- של Linux הוא non-preemptive, יש שני אירועים נפרדים:  גילוי הצורך ב-context switch  ביצוע של context switch

5 מערכות הפעלה - תרגול 45 (c) ארז חדד 2003 גילוי הצורך בהחלפת הקשר  בארבעה מצבים מגלים צורך ב context switch 1. בתגובה על פסיקת שעון – לאחר שתהליך כילה את ה-time slice שלו (בעקבות השגרה scheduler_tick()). 2. בחזרה של תהליך מהמתנה – פסיקה שבה משתחרר מהמתנה תהליך בעל עדיפות טובה יותר (משאר התהליכים המוכנים לריצה, כולל התהליך הרץ כרגע) 3. בטיפול בקריאת מערכת חוסמת הגורמת לתהליך הקורא לעבור להמתנה, כך שהמעבד מתפנה להריץ תהליך אחר. 4. כאשר תהליך מוותר על המעבד מרצונו בקריאת מערכת כגון sched_yield().  שני המצבים הראשונים גורמים להדלקת דגל need_resched של התהליך, אשר נבדק לפני החזרה לuser mode.  מצב 3 ו-4 גורמים לקריאה ישירה ל זמן ולהחלפת הקשר

6 מערכות הפעלה - תרגול 46 (c) ארז חדד 2003 ביצוע החלפת הקשר ב-Linux, פונקצית schedule(). schedule() היא הפונקציה היחידה המפעילה את החלפת ההקשר. schedule() בוחרת מי יהיה התהליך הבא לזימון למעבד  כפי שראינו בתרגול הקודם קוראת לפונקציה context_switch() לביצוע החלפת ההקשר. שתי הפונקציות מתבצעות בפסיקות חסומות על-מנת למנוע הפעלה רקורסיבית של הזמן והחלפת ההקשר, דבר העלול לגרום לשיבוש פעולת מערכת ההפעלה  כפי שנראה בתרגול הבא

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

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

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

10 מערכות הפעלה - תרגול 410 (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)

11 מערכות הפעלה - תרגול 411 (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 מאחסן את הרגיסטרים של היחידה המתימטית

12 מערכות הפעלה - תרגול 412 (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_mm.... קוד החלפת איזורי הזיכרון switch_to(prev, next, prev); return prev; }

13 מערכות הפעלה - תרגול 413 (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 ולכן יש לשמור אותם ולשחזר אותם בהמשך הרצת התהליך

14 מערכות הפעלה - תרגול 414 (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

15 מערכות הפעלה - תרגול 415 (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(לא סטנדרטי ל C): #define FASTCALL __attribute__(regparm(3))  עד 3 פרמטרים מועברים ברגיסטרים eax, edx, ecx (משמאל לימין)  לכן, prev_p מועבר בתוך eax ו-next_p בתוך edx למה אי אפשר לקרוא ל __switch_to בצורה רגילה?  בגלל תהליך חדש – ret_from_fork,שנראה בהמשך.

16 מערכות הפעלה - תרגול 416 (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 הוא תהליך שרץ פעם ראשונה, הכתובת היא אחרת כפי שנראה בהמשך.

17 מערכות הפעלה - תרגול 417 (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

18 מערכות הפעלה - תרגול 418 (c) ארז חדד 2003 שאלה.... למה context switch מורכב משלושה קטעי קוד נפרדים?  context_switch() - פונקצית C כללית הנמצאת בספריה של ה-kernel.  switch_to – מאקרו באסמבלר, ספציפי למעבד, מופיע בספריה מיוחדת למעבד i386.  __switch_to – פונקצית C, ספציפית למעבד.

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

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

21 מערכות הפעלה - תרגול 421 (c) ארז חדד 2003 שמירת הרגיסטרים של Kernel Mode ומה לגבי שמירת הקשר הביצוע בתוך הגרעין?  המאקרו switch_to אינו משפיע מבחינת ערכי רגיסטרים על context_switch(), משום שהוא מופעל ממש לפני החזרה מהפונקציה  ebp, esi, edi - נשמרים במחסנית ומשוחזרים במאקרו switch_to. ebx – ערך ebx מלפני הקריאה ל-switch_to אינו בשימוש לאחר הקריאה ולכן לא נשמר (כן נשמר ומשוחזר ע"י context_switch())  ecx, edx, eax - נשמרים במחסנית ע"י הפונקציה schedule() המאקרו switch_to אינו משתמש בהם בין הפונקציה schedule() לפונקציה context_switch() מתקיימים יחסי caller- callee (פונקציה קוראת / פונקציה נקראת, כפי שראינו בתרגול 2), לכן בפונקציה schedule() לא מניחים שערכי הרגיסטרים פרט ל-ebx, ebp, esi, edi משתמרים  esp ו-eip נשמרים בתוך thread_struct לפני החלפת ההקשר ב switch_to.  הרגיסטרים של הסגמנטים אינם משתנים בהחלפת הקשר ולכן אינם נשמרים למעט fs ו-gs, שלפעמים נמצאים בשימוש מיוחד ע"י תהליכים ולכן נשמרים  בסיס מחסנית הגרעין השמור ב thread_struct.esp0 נשמר ב TSS

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

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

24 מערכות הפעלה - תרגול 424 (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; childregs מצביע על תחילת המקום בו מאוחסנים הרגיסטרים במחסנית childregs = ((struct pt_regs *)(8192 + (unsigned long) p)) – 1; העתקת הרגיסטרים ממחסנית הגרעין של האב למחסנית הגרעין של הבן struct_cpy(childregs, regs); כזכור מתרגול 2, לתהליך הבן מוחזר ערך 0 מביצוע fork() childregs->eax = 0; יצירת תהליך חדש ב-Linux

25 מערכות הפעלה - תרגול 425 (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; זו הכתובת ש switch_to ידחוף למחסנית בפקודה pushl next->thread.eip ושאותה יוציא מהמחסנית __switch_to. (ראה שקף 16) /* save fs and gs registers in thread field */ /* copy saved math regs in thread field from father to son */

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

27 מערכות הפעלה - תרגול 427 (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

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

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

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


Download ppt "מערכות הפעלה תרגול 4 – החלפת הקשר (context switch)"

Similar presentations


Ads by Google