מערכות הפעלה
(context switch) – החלפת הקשר4תרגול
מערכות הפעלה - תרגול 4 2(c) 2003 ארז חדד
תוכן התרגול
) החלפת הקשרcontext switch-ב (Linux-יצירת תהליך חדש בLinux-סיום ביצוע תהליך בLinux
מערכות הפעלה - תרגול 4 3(c) 2003 ארז חדד
מהי החלפת הקשר?
"מעבד מריץ מספר תהליכים "בו-זמנית המעבד מריץ תהליך אחד לפרק זמן כלשהו ואז משעה את
ביצועו ועובר להמשיך להריץ תהליך אחר – "מיתוג" בין התהליכים המתבצעים
) "לכל תהליך יש "הקשר ביצועexecution context (המכיל את כל המידע הדרוש לביצוע התהליך
מחסניות, רגיסטרים, דגלים, תכולת זיכרון, קבצים פתוחים פעולת המיתוג שומרת את הקשר התהליך הנוכחי
וטוענת למעבד את הקשר הביצוע של התהליך הבא הקשר התהליך הנוכחי מתחלף – מכאן שם הפעולה
"החלפת הקשר"
מערכות הפעלה - תרגול 4 4(c) 2003 ארז חדד
Linuxהחלפת הקשר ב-
בLinux לא ניתן לבצע החלפת הקשר כפויה לתהליך .kernel mode-שנמצא ב
,אם בעקבות פסיקה נוצר צורך לבצע החלפת הקשרהיא תתבצע לאחר שהתהליך יסיים את הפעולה
.user mode, לפני חזרתו ל-kernel-modeבבגלל שהkernel של -Linux הוא non-preemptive ,יש
שני אירועים נפרדים:-גילוי הצורך בcontext switch ביצוע שלcontext switch
מערכות הפעלה - תרגול 4 5(c) 2003 ארז חדד
גילוי הצורך בהחלפת הקשרבארבעה מצבים מגלים צורך ב context switch
שלו time slice – לאחר שתהליך כילה את ה-בתגובה על פסיקת שעון1.). ()scheduler_tick(בעקבות השגרה
פסיקה שבה משתחרר מהמתנה תהליך – בחזרה של תהליך מהמתנה2. כולל ,בעל עדיפות טובה יותר (משאר התהליכים המוכנים לריצה
התהליך הרץ כרגע) הגורמת לתהליך הקורא לעבור בקריאת מערכת חוסמתבטיפול 3.
להמתנה, כך שהמעבד מתפנה להריץ תהליך אחר. בקריאת מערכת כגון מוותר על המעבד מרצונוכאשר תהליך 4.
sched_yield(). שני המצבים הראשונים גורמים להדלקת דגלneed_resched
.user mode החזרה ללפני התהליך, אשר נבדקשל זמן ולהחלפת הקשר לקריאה ישירה ל מים גור4 ו-3מצב
מערכות הפעלה - תרגול 4 6(c) 2003 ארז חדד
, Linuxביצוע החלפת הקשר ב-().scheduleפונקצית
schedule היא הפונקציה היחידה המפעילה את ()החלפת ההקשר.
schedule בוחרת מי יהיה התהליך הבא לזימון ()למעבד
כפי שראינו בתרגול הקודם קוראת לפונקציהcontext_switch ()החלפת לביצוע
ההקשר.על-מנת בפסיקות חסומות מתבצעות שתי הפונקציות
למנוע הפעלה רקורסיבית של הזמן והחלפת ההקשר, דבר העלול לגרום לשיבוש פעולת מערכת ההפעלה
הבא בתרגול הראנכפי ש
מערכות הפעלה - תרגול 4 7(c) 2003 ארז חדד
,Linuxביצוע החלפת הקשר ב-סדר הפעולות.
:החלפת הקשר היא בקירוב רצף הביצוע הבאשמירת נתוני הקשר התהליך הנוכחי. 1.מעבר למחסנית הגרעין של התהליך הבא (שהופך 2.
להיות התהליך הנוכחי החדש). טעינת נתוני הקשר התהליך הנוכחי החדש. 3.קפיצה לכתובת הבאה לביצוע של התהליך הנוכחי 4.
החדש.
מערכות הפעלה - תרגול 4 8(c) 2003 ארז חדד
Linuxהחלפת הקשר ב--מרבית ההקשר של תהליך בLinux מאוחסן במתאר התהליך
ולכן אין צורך "לשמור" ו"לטעון" אותו מחדש בכל החלפת הקשר.
נשמרים ונטענים בעיקר הרגיסטרים והדגלים השמירה והטעינה – במחסנית הגרעין של התהליך ובמתאר התהליך
threadבשדה פעולת החלפת ההקשר כוללת גם החלפת אזורי הזיכרון
: מאלו של התהליך הנוכחי User Modeאליהם המעבד ניגש ב-לאלו של התהליך הבא
,עם זאת, פעולת החלפת ההקשר מתבצעת באזור הזיכרון של הגרעיןשאינו מתחלף
במהלך החלפת הקשר לא משנים את ערכי הרגיסטרים של הסגמנטים)cs, ds, ss, es .למרות שאזור הזיכרון של התהליך אכן מוחלף ,(
הסבר בתרגול על הזיכרון הוירטואלי
מערכות הפעלה - תרגול 4 9(c) 2003 ארז חדד
Task State Segment (1)
אזורTask State Segment – TSS ,הוא אזור זיכרון בגרעין המכיל מידע מתוך הקשר התהליך הנוכחי המתבצע במעבד.
-לכל מעבד בLinux יש אזור TSS.משלו ) קיומו של אזור זה הוא אילוץ של החומרהIA32(
המעבד קורא את כתובת מחסנית הגרעין של התהליך הנוכחי משדהKernel Mode בעת מעבר ל-TSSב-
-הTSS משמש בחומרה לפעולות נוספות כגון בקרת גישה בפעולות I/O-הTSS של כל המעבדים מוכלים במערך init_tss.-בעת ביצוע החלפת הקשר, מעדכנים שדות בTSS.
מערכות הפעלה - תרגול 4 10(c) 2003 ארז חדד
Task State Segment (2)
ההגדרות נמצאות בקובץ הגרעיןinclude/asm/processor.h
struct tss_struct {
..
unsigned long esp0;
..
};
struct tss_struct init_tss[NR_CPUS];
מצביע לבסיס מחסנית הגרעין של התהליך הנוכחי במעבד
)kernel mode בכניסה ל-esp(ערך
מערכות הפעלה - תרגול 4 11(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;..
};
מצביע לכתובת הבסיס של מחסנית הגרעין של התהליך
מאחסן את המצביע לכתובת הבאה לביצוע לאחר החלפת הקשר
מאחסן את המצביע לראש המחסנית (בגרעין) בהחלפת הקשר
gs ו-fsמאחסן את רגיסטרי הסגמנטים
מאחסן את הרגיסטרים של היחידה המתימטית
מערכות הפעלה - תרגול 4 12(c) 2003 ארז חדד
()context_switchהפונקציה
הפונקציה המבצעת את החלפת ההקשר נקראתcontext_switch()
קובץ גרעיןkernel/sched.c פונקציה זו מבצעת את החלפת איזורי הזיכרון ואז קוראת למאקרו
switch_toהמבצע את פעולות הטעינה והשמירה הפונקציהcontext_switch היא חלק מאלגוריתם הזימון החדש. בגרסה ()
switch_to קיים רק X.2.4הסטנדרטית של הגרעין
inline task_t *context_switch(task_t *prev, task_t *next) {switch_mm.... קוד החלפת איזורי הזיכרוןswitch_to(prev, next, prev);return prev;
}
מערכות הפעלה - תרגול 4 13(c) 2003 ארז חדד
switch_to (1)המאקרו
המאקרו מוגדר בקובץ הגרעיןinclude/asm/system.h :הקריאה למאקרוswitch_to(prev, next, last)
prevמצביע למתאר התהליך הנוכחי, שמוותר על המעבד nextמצביע למתאר התהליך הבא, שמקבל את המעבד last .הוא פרמטר שכבר אינו בשימוש באלגוריתם הזימון החדש
הסטנדרטית, פרמטר זה מצביע לאחר החזרה X.2.4בגרסת אל התהליך switch_to על מתאר התהליך ממנו בוצע switch_toמ-
הנוכחי
movl prev, %eaxmovl next, %edxpushl %esipushl %edipushl %ebp
) מניח שרגיסטרים אלוgccהקומפיילר ( ולכן ישswitch_toאינם משתנים עד סוף
לשמור אותם ולשחזר אותם בהמשך הרצת התהליך
מערכות הפעלה - תרגול 4 14(c) 2003 ארז חדד
switch_to (2)המאקרו
movl %esp, prev->thread.espmovl next->thread.esp, %espmovl $1f, prev->thread.eippushl next->thread.eipjmp __switch_to 1:popl %ebppopl %edipopl %esi
החלפת מחסניות הגרעין מזו – זוnext לזו של prevשל
למעשה נקודת החלפת ההקשר ימשיך מהכתובת של prevהתהליך " כשיחזור לרוץ1התוית "
ימשיך לרוץ מכתובת זו nextהתהליך switch_to__בסיום
שחזור הרגיסטרים ממחסנית הגרעיןswitch_to לפני סיום nextשל
switch_to__ לפונקציה קפיצה
מערכות הפעלה - תרגול 4 15(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.שנראה בהמשך,
מערכות הפעלה - תרגול 4 16(c) 2003 ארז חדד
switch_to() (2)הפונקציה __
פונקציה זו מופעלת באמצעות קפיצה מתוך המאקרוswitch_to למעשה, מתוך הפונקציה) context_switch (()
כאשר הפרמטרים כבר ברגיסטרים.jmp __switch_to
__-מכיוון שswitch_to מוגדרת כפונקציה, הקוד שלה () ששולפת כתובת חזרה מהמחסנית retמסתיים בפקודת
וקופצת אליה..המחסנית היא מחסנית הגרעין של התהליך הנוכחי החדש כתובת החזרה היאnext->thread.eip כפי שהוכנסה בקוד של המאקרו
switch_to' של המשך ביצוע 1. ברוב המקרים, זוהי כתובת התוית '().context_switch בתוך הפונקציה switch_toהמאקרו
אםnext ,כפי הכתובת היא אחרת הוא תהליך שרץ פעם ראשונה שנראה בהמשך.
מערכות הפעלה - תרגול 4 17(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->fsmovl %gs, prev->gsif (prev->fs | prev->gs | next->fs | next->gs) {
..movl next->fs, %fsmovl next->gs, %gs..
}/* load debug registers *//* load IO permission bitmap */return;
שמירה ושחזור gs ו-fsשל
שמירה ושחזור של הרגיסטריםשל היחידה המתימטית
עדכון מצביע מחסנית הגרעיןTSSשל התהליך הנוכחי ב-
מערכות הפעלה - תרגול 4 18(c) 2003 ארז חדד
שאלה ....
למהcontext switch שלושה קטעי מ מורכבקוד נפרדים?
context_switch פונקצית - ()C כללית הנמצאת .kernel ה-בספריה של
switch_to ,מאקרו באסמבלר, ספציפי למעבד – .i386מופיע בספריה מיוחדת למעבד
__switch_to פונקצית – C .ספציפית למעבד ,
(c) 2003 19מערכות הפעלה - תרגול 4ארז חדד
context_switch:
ret
eip
next המשך הביצוע של
$1febpediesi
מסגרת שלcontext_switch()
……
switch_to:
movl $1f, prev->thread.eip
pushl next->thread.eip
1:
switch_to:__ ……
…
$1f
prev
task_struct
thread.eipthread.esp
מחסנית הגרעין
של התהליך
prevebpediesi
מסגרת שלcontext_switch()
nexttask_struct
esp
מחסנית הגרעין
של התהליך
next
thread.eip$1f
thread.esp
$1febpediesi
מסגרת שלcontext_switch()
מערכות הפעלה - תרגול 4 20(c) 2003 ארז חדד
Userשמירת הרגיסטרים של Mode
שם רגיסטרמה מכילאיפה נשמרמתי נשמרמייד עם תחילת
kernelהמעבר לmode
ע"י חומרה במחסנית הגרעין
מצביע למחסנית רגילה
ss:esp
בעת קפיצה לטיפול בפסיקה
נשמר באופן אוטומטי במחסנית הגרעין
eflags
בעת קפיצה לטיפול בפסיקה
נשמר באופן אוטומטי במחסנית הגרעין אחרי
eflags
cs:eipכתובת החזרה
בתחילת שגרת הטיפול בפסיקה
נשמרים במחסנית הגרעין דרך SAVE_ALL
es,ds,eax,
ebp,edi,esi,edx,
ecx,ebx
-מרבית הרגיסטרים שבהם התהליך משתמש בUser Mode (ראינו דוגמה חלקית בתרגול Kernel Modeנשמרים במעבר ל-
2(
מערכות הפעלה - תרגול 4 21(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
מערכות הפעלה - תרגול 4 22(c) 2003 ארז חדד
Linux (1)יצירת תהליך חדש ב-
קריאות המערכת המשמשות ליצירת תהליכים()) משתמשות בפונקציה פנימית forkחדשים (כדוגמת
() לבניית ההקשר של do_forkשל הגרעין הקרויה התהליך החדש
קובץ גרעיןkernel/fork.c הפונקציהdo_fork מעתיקה את מרבית הנתונים ()
ממתאר תהליך האב למתאר חדש של תהליך הבן שהיא יוצרת
) קבצים פתוחיםfile descriptors בעלות משותפת על ,(משאבי מערכת
העתקת תכולת הזיכרון מתבצעת בשיטה מיוחדת – פרטיםבתרגולים הבאים
מערכות הפעלה - תרגול 4 23(c) 2003 ארז חדד
Linux (2)יצירת תהליך חדש ב-
הפונקציהdo_fork() בונה מחסנית גרעין לתהליך הבן ()copy_threadע"י קריאה לפונקציה
מתאר תהליך הבן מקושר לרשימת התהליכים ו"בניSET_LINKSמשפחתו" ע"י המאקרו
-הקישור בין הpid של תהליך הבן למתאר תהליך הבן ()hash_pidמופעל ע"י קריאה ל-
תהליך הבן מועבר למצבTASK_RUNNING ומוכנס ()wake_up_process ע"י קריאה ל-runqueueל-
לסיום, הפונקציהdo_fork()-מחזירה את ה pid של תהליך הבן, וערך זה מוחזר לבסוף לתהליך האב
מערכות הפעלה - תרגול 4 24(c) 2003 ארז חדד
copy_thread() (1)הפונקציה
פונקציה זו (קובץ גרעיןarch/i386/kernel/process.c מאתחלת את תכולת ( במתאר תהליך הבן. להלן threadמחסנית הגרעין של תהליך הבן ואת שדה
תיאור של עיקר הקודpמצביע למתאר תהליך הבן regs מצביע לרגיסטרים שאוחסנו במחסנית הגרעין של האב באמצעות
kernel mode במהלך המעבר ל-SAVE_ALLהקפיצה לפסיקה ו- struct pt_regs הוא רשומה המכילה את ערכי הרגיסטרים בדיוק בסדר בו הם
SAVE_ALLמאוחסנים במחסנית באמצעות הקפיצה לפסיקה ו- struct pt_regs* childregs;
childregsמצביע על תחילת המקום בו מאוחסנים הרגיסטרים במחסנית childregs = ((struct pt_regs *)(8192 + (unsigned long) p)) – 1;
העתקת הרגיסטרים ממחסנית הגרעין של האב למחסנית הגרעין של הבןstruct_cpy(childregs, regs);
()fork מביצוע 0, לתהליך הבן מוחזר ערך 2כזכור מתרגול childregs->eax = 0;
Linuxיצירת תהליך חדש ב-
מערכות הפעלה - תרגול 4 25(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;
pushl next->thread.eip ידחוף למחסנית בפקודהswitch_toזו הכתובת ש )16. (ראה שקף switch_to__ושאותה יוציא מהמחסנית
/* save fs and gs registers in thread field */
/* copy saved math regs in thread field from father to son */
מערכות הפעלה - תרגול 4 26(c) 2003 ארז חדד
()ret_from_forkהפונקציה
פונקציה זו מופעלת כאשר תהליך הבן מזומן לראשונה למעבדלאחר החלפת הקשר
הפונקציה מוגדרת בקובץ הגרעיןarch/i386/kernel/entry.Sret_from_fork:check need_resched
…jmp ret_from_sys_call
ביצוע 2כפי שראינו בתרגול ,ret_from_sys_call יגרום לתהליך לאחר שנשלפו כל הרגיסטרים user modeהבן לחזור ל-
מהמחסנית-למעשה, ביצוע הקוד בret_from_fork יגרום לסיום הקריאה
fork 0() בתהליך הבן עם ערך מוחזר
מערכות הפעלה - תרגול 4 27(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
מערכות הפעלה - תרגול 4 28(c) 2003 ארז חדד
)1סיום ביצוע תהליך (
תהליך מסיים את ביצוע הקוד ע"י קריאת המערכתexit()
-אם קוד התהליך לא קורא במפורש לexit מתבצעת ,()() main() לאחר שהפונקציה exitקריאה אוטומטית ל-
libcחוזרת, מתוך הספריה __ מתוך פונקצית הספריהlibc_start_main שקוראת ()
() בתחילת ביצוע התכניתmainל- ביצוע קוד תהליך יכול גם להיקטע בעקבות אירועים
נוספים תקלה לא מטופלת במהלך ביצוע הקוד, כגון גישה לא חוקית
0לזיכרון או חלוקה ב-הריגת תהליך אחד על-ידי תהליך אחר
מערכות הפעלה - תרגול 4 29(c) 2003 ארז חדד
)2סיום ביצוע תהליך ( הפונקציהdo_exit מופעלת בכל מקרה של סיום ()
ביצוע התהליך קובץ גרעיןkernel/exit.c
:בין השאר, פונקציה זו מבצעת את הפעולות הבאותמשחררת את המשאבים שבשימוש התהליך שדה את מעדכנתexit_code במתאר התהליך להכיל את
()exitהערך המוחזר ע"י מעדכנת קשרי משפחה: כל בניו של התהליך שסיים
initהופכים להיות בנים של -מעבירה את מצב התהליך לTASK_ZOMBIE-קוראת לschedule שמוציאה את התהליך ,()
ומזמנת תהליך אחר לביצוע במעבד. ביצוע runqueueמה-switch_toהתהליך מסתיים סופית בביצוע
מערכות הפעלה - תרגול 4 30(c) 2003 ארז חדד
)3סיום ביצוע תהליך (
מתאר התהליך מפונה רק כאשר תהליך האב מקבלחיווי על סיום התהליך, באמצעות קריאה כדוגמת
wait() פינוי מתאר התהליך מבוצע ע"י הפונקציה
release_task() קובץ גרעיןkernel/exit.c
פונקציה זו, בין השאר, מנתקת את התהליך מרשימת pid) וממנגנון הקישור ל-REMOVE_LINKSהתהליכים (
(unhash_pid()) ומפנה את השטח המוקצה למתאר ,התהליך ומחסנית הגרעין