1 / 39

מערכות הפעלה

מערכות הפעלה. תרגול 3 – תהליכים ב- Linux (1). תוכן התרגול. מבוא לתהליכים ב- Linux API לעבודה עם תהליכים מבוא לניהול תהליכים בתוך הגרעין מתאר התהליך ( process descriptor ) רשימת התהליכים ( process list ) מאגר התהליכים המוכנים לריצה ("הטווח הקצר") תורי המתנה ("הטווח הבינוני / ארוך").

hayley
Download Presentation

מערכות הפעלה

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

  2. תוכן התרגול • מבוא לתהליכים ב-Linux • API לעבודה עם תהליכים • מבוא לניהול תהליכים בתוך הגרעין • מתאר התהליך (process descriptor) • רשימת התהליכים (process list) • מאגר התהליכים המוכנים לריצה ("הטווח הקצר") • תורי המתנה ("הטווח הבינוני / ארוך") מערכות הפעלה - תרגול 3

  3. מבוא לתהליכים ב-Linux (1) • תהליך (process) הוא ביצוע סדרתי של משימה, המוגדרת על-ידי תכנית (program) • תהליך = מופע (instance) של ביצוע תכנית • תהליך נקרא גם task במקומות שונים • מספר תהליכים מתבצעים "בו זמנית" על המעבד במחשב • למעשה – המעבד "ממתג" בין התהליכים בתדירות גבוהה באמצעות מנגנון החלפת הקשר. פרטים בתרגול הבא • עבור מערכת ההפעלה, תהליך הינו יישות עצמאית הצורכת משאבים • זיכרון, זמן מעבד, שטח דיסק וכו' • לכל תהליך ב-Linux יש מזהה הקרוי PID – Process IDentifier • מספר שלם בן 32 ביט ייחודי לתהליך (עד 32K תהליכים מטעמי תאימות הסטורית) • ערכי ה-pid ממוחזרים מתהליכים שסיימו לתהליכים חדשים שנוצרים מערכות הפעלה - תרגול 3

  4. מבוא לתהליכים ב-Linux (2) • באיתחול Linux גרעין מערכת ההפעלה יוצר שני תהליכים בלבד • swapper (pid=0) – משמש לניהול זיכרון • init (pid=1) – ממנו נוצרים כל שאר התהליכים במערכת • כל תהליך נוסף נוצר ב-Linux כעותק של תהליך קיים • התהליך המקורי נקרא תהליך אב (או הורה) • התהליך החדש נקרא תהליך בן • תהליך הבן נוצר בעקבות ביצוע קריאת מערכת כדוגמת fork() על-ידי תהליך האב • תהליך אב יכול ליצור יותר מתהליך בן אחד מערכות הפעלה - תרגול 3

  5. מבוא לתהליכים ב-Linux (3) • תהליך יכול לאחר היווצרו לבצע משימה שונה מאביו • על-ידי הסתעפות בקוד התכנית הקיימת, לאחר ההתפצלות מהאב • על-ידי טעינת משימה חדשה (תכנית חדשה) לביצוע • למשל, על-ידי קריאת המערכת execv() • תהליך אב יכול לבדוק סיום של כל תהליך בן שלו • אך לא של "נכדים", "נינים", "אחים" וכדומה • אב יכול להמתין לסיום בן לפני המשך פעולתו • למשל, על-ידי קריאת המערכת wait() מערכות הפעלה - תרגול 3

  6. מבוא לתהליכים ב-Linux (4) • כדי לאפשר לאב לקבל מידע על סיום הבן, לאחר שתהליך מסיים את פעולתו הוא עובר למצב מיוחד – zombie – שבו התהליך קיים כרשומת נתונים בלבד ללא שום ביצוע משימה • הרשומה נמחקת לאחר שהאב קיבל את המידע על סיום הבן • מה קורה לתהליך שהופך ל"יתום" (orphan) לאחר שאביו כבר סיים? • התהליך הופך להיות בן של init • התהליך init ממשיך להתקיים לאורך כל פעולתה של מערכת ההפעלה • אחד מתפקידיו העיקריים - המתנה לכל בניו, כדי לפנות את נתוניהם לאחר סיום מערכות הפעלה - תרגול 3

  7. API לתהליכים ב-Linux (1) • קריאת המערכת fork() • תחביר: pid_t fork(); • פעולה: מעתיקה את תהליך האב לתהליך הבן וחוזרת בשני התהליכים • קוד זהה (ומיקום בקוד) • זיכרון זהה (משתנים וערכיהם, חוצצים) • סביבה זהה (קבצים פתוחים, file descriptors, ספרית עבודה נוכחית) • פרמטרים: אין • ערך מוחזר: • במקרה של כישלון: -1 לאב (אין בן) • במקרה של הצלחה: לבן מוחזר 0 ולאב מוחזר ה-pid של הבן מערכות הפעלה - תרגול 3

  8. API לתהליכים ב-Linux (2) • לאחר פעולת fork() מוצלחת, אמנם יש לאב ולבן את אותם משתנים בזיכרון, אך בעותקים נפרדים • כלומר, שינוי ערכי המשתנים אצל האב לא ייראה אצל הבן, וההיפך • כמו כן, תהליך הבן הוא תהליך נפרד מתהליך האב לכל דבר. בפרט, יש לו pid משלו • מה מדפיס הקוד הבא? main() { fork(); printf(“hello”); } מערכות הפעלה - תרגול 3

  9. API לתהליכים ב-Linux (3) • תשובות אפשריות (בהנחה ש-fork() הצליחה): hellohello hheellollo • הסיבה: שני תהליכים כותבים פלט בצורה לא מתואמת • מבנה תכנית אופייני המשתמש ב-fork(): status = fork(); if (status < 0) // fork() failed – handle error (e.g. message & exit) if (status == 0) // son process – do son code else // father process – do father code מערכות הפעלה - תרגול 3

  10. API לתהליכים ב-Linux (4) • קריאת המערכת execv() • תחביר: int execv(const char *filename, char *const argv[]); • פעולה: טוענת תכנית חדשה לביצוע על-ידי התהליך הקורא • פרמטרים: • filename – מסלול אל הקובץ המכיל את התכנית לטעינה • argv – מערך מצביעים למחרוזות המכיל את הפרמטרים עבור התכנית. האיבר הראשון מקיים argv[0] == filename או רק מכיל את שם קובץ התכנית. האיבר שאחרי הפרמטר האחרון מכיל NULL • ערך מוחזר: • במקרה של כישלון: -1 • במקרה של הצלחה: הקריאה אינה חוזרת. איזורי הזיכרון של התהליך מאותחלים לתכנית החדשה שמתחילה להתבצע מההתחלה. מערכות הפעלה - תרגול 3

  11. API לתהליכים ב-Linux (5) • מה ידפיס הקוד הבא? main() { char *argv[] = {“date”, NULL}; execv(“/bin/date”, argv); printf(“hello”); } • התשובה: • אם execv() מצליחה: את התאריך והשעה • אם execv() נכשלת: hello מערכות הפעלה - תרגול 3

  12. API לתהליכים ב-Linux (6) • דוגמה אופיינית לשילוב fork() עם execv(): pid = fork(); if (pid < 0) { handle fork() error } if (pid > 0) // do father code else execv(“son_prog”, argv_son); מערכות הפעלה - תרגול 3

  13. API לתהליכים ב-Linux (7) • קריאת המערכת exit() • תחביר: void exit(int status); • פעולה: מסיימת את ביצוע התהליך הקורא ומשחררת את כל המשאבים שברשותו. התהליך עובר למצב zombie עד שתהליך האב יבקש לבדוק את סיומו ואז יפונה לחלוטין • פרמטרים: • status – ערך סיום המוחזר לאב אם יבדוק את סיום התהליך • ערך מוחזר: הקריאה אינה חוזרת מערכות הפעלה - תרגול 3

  14. API לתהליכים ב-Linux (8) • קריאת המערכת wait() • תחביר: pid_t wait(int *status); • פעולה: גורמת לתהליך הקורא להמתין עד אשר אחד מתהליכי הבן שלו יסיים • פרמטרים: • status – מצביע למשתנה בו יאוחסן סטטוס הבן שסיים • ערך מוחזר: • אם אין בנים, או שכל הבנים כבר סיימו וכבר בוצע להם wait() - חזרה מיד עם ערך -1 • אם יש בן שסיים ועדיין לא בוצע לו wait() (zombie) – חזרה מייד עם ה-pid של הבן הנ"ל ועם סטטוס הסיום שלו. מאקרו-ים שונים מאפשרים לקבל מתוך הסטטוס מידע על הבן. למשל WEXITSTATUS (status) יתן את ערך הסיום של בן שסיים (הערך שהעביר כארגומנט ל-exit()). • אחרת – המתנה עד שבן כלשהו יסיים מערכות הפעלה - תרגול 3

  15. API לתהליכים ב-Linux (9) • דוגמת קוד אופיינית בה האב מחכה לסיום כל תהליכי הבן: while (wait(&status) != -1); • קריאה שימושית נוספת: waitpid() – המתנה לסיום בן מסוים pid_t waitpid(pid_t pid, int *status, int options); • ניתן למשל, באמצעות options, לבחור רק לבדוק אם הבן סיים (ערך WNOHANG) או להמתין לסיום הבן (ערך 0) מערכות הפעלה - תרגול 3

  16. API לתהליכים ב-Linux (10) • קריאת המערכת getpid() • תחביר: pid_t getpid() • פעולה: מחזירה לתהליך הקורא את ה-pid של עצמו • פרמטרים: אין • ערך מוחזר: ה-pid של התהליך הקורא • קריאה שימושית דומה: getppid() מחזירה את ה-pid של תהליך האב של התהליך הקורא • מה המשמעות של getppid() == 1 עבור תהליך משתמש טיפוסי? • תשובה: תהליך האב שיצר את התהליך הנוכחי סיים מערכות הפעלה - תרגול 3

  17. אתחול תהליכים ב-Linux • משתמשים מתחברים לעבודה ב-Linux דרך מסופים • מסוף = מסך + מקלדת (מקומי או מרוחק) • התהליך init יוצר עבור כל מסוף של Linux תהליך בן הטוען ומבצע את המשימות הבאות לפי הסדר: • איתחול של המסוף בתכנית getty • תכנית login המאפשרת למשתמש להיכנס למערכת • לאחר שאושרה כניסת המשתמש: תכנית shell(כמו tcsh או bash) המאפשרת למשתמש להעביר פקודות למערכת ההפעלה • כאשר ה-shell מקבל פקודה, הוא מייצר תהליך בן שמבצע אותה, ממתין לסיום הבן ואז קורא את הפקודה הבאה מערכות הפעלה - תרגול 3

  18. אתחול תהליכים ב-Linux (2) init Pid=1 fork() fork() fork() wait() Pid=7223 Pid=30498 Pid=8837 exit() exec(getty) exec(getty) exec(getty) exec(login) exec(login) exec(shell) shell fork() wait() Pid=5562 exec(command) exit() מערכות הפעלה - תרגול 3

  19. ניהול תהליכים בגרעין (1) • לכל תהליך ב-Linux קיים בגרעין מתאר תהליך (process descriptor), שהוא רשומה מסוג task_struct (קובץ גרעין include/linux/sched.h) המכילה: • מצב התהליך • עדיפות התהליך • מזהה התהליך (pid) • מצביע לטבלת איזורי הזיכרון של התהליך • מצביע לטבלת הקבצים הפתוחים של התהליך • מצביעים למתארי תהליכים נוספים (רשימה מקושרת) • מצביעים למתאר תהליך האב ו"קרובי משפחה" נוספים • מסוף איתו התהליך מתקשר • ועוד.. מערכות הפעלה - תרגול 3

  20. ניהול תהליכים בגרעין (2) • מצב התהליך נמצא בשדה state,שהוא משתנה בגודל 32 ביט המתפקד כמערך ביטים • בכל זמן שהוא, בדיוק אחד מהביטים ב-state דלוק בהתאם למצב התהליך באותו זמן • Linux מגדירה את המצבים הבאים לכל תהליך: • TASK_RUNNING – התהליך רץ או מוכן לריצה, כלומר נמצא בטווח הקצר • TASK_INTERRUPTIBLE – התהליך ממתין לאירוע כלשהו (טווח בינוני/ארוך) אך ניתן להפסיק את המתנת התהליך ולהחזירו למצב TASK_RUNNING באמצעות שליחת אות כלשהו לתהליך. זהו מצב ההמתנה הנפוץ. מערכות הפעלה - תרגול 3

  21. ניהול תהליכים בגרעין (3) • TASK_UNINTERRUPTIBLE – התהליך ממתין לאירוע כלשהו (בדומה ל- TASK_INTERRUPTIBLE) אך פרט לאירוע לו הוא ממתין, לא ניתן ל"העיר" את התהליך • מצב המתנה נדיר לשימוש – למשל כאשר התהליך מבקש לגשת לחומרה ומערכת ההפעלה צריכה לסרוק אחר החומרה ללא הפרעה • TASK_STOPPED – ריצת התהליך נעצרה בצורה מבוקרת על-ידי תהליך אחר (בדרך-כלל debugger או tracer) • TASK_ZOMBIE – ריצת התהליך הסתיימה, אך תהליך האב של התהליך שסיים עדיין לא ביקש מידע על סיום התהליך באמצעות קריאה כדוגמת wait(). התהליך קיים כמתאר בלבד • את ערך השדה state ניתן לשנות בהצבה ישירה או על-ידי המאקרו set_task_state או set_current_state (קובץ גרעין include/linux/sched.h) מערכות הפעלה - תרגול 3

  22. ניהול תהליכים בגרעין (4) • לכל תהליך יש מחסנית נוספת הקרויה kernel mode stack, כלומר "מחסנית גרעין" • מחסנית זו משמשת את גרעין מערכת ההפעלה בטיפול באירועים במהלך ריצת התהליך • פסיקות בכלל • קריאות מערכת בפרט • מחסנית הגרעין של כל תהליך מאוחסנת באיזור הזיכרון של הגרעין • כאשר במהלך ריצת התהליך מתבצע מעבר בין user mode ו-kernel mode, מתבצעת החלפת מחסניות (שינוי ערכי ss ו-esp) בין המחסנית הרגילה של התהליך ומחסנית הגרעין • ערכי ss:esp המצביעים למחסנית הרגילה נשמרים על-ידי המעבד במחסנית הגרעין מיד עם המעבר ל-kernel mode ומשוחזרים במעבר החוזר ל-user mode מערכות הפעלה - תרגול 3

  23. ניהול תהליכים בגרעין (5) • מחסנית הגרעין מאוחסנת יחד עם מתאר התהליך בקטע זיכרון אחד בגודל 8KB, המתחיל בכתובת שהיא כפולה של 8KB (213) 0x015fbfff Kernel Mode Stack union task_union { struct task_struct task; unsigned long stack[2048]; }; המחסנית לא דורסת את מתאר התהליך מפני שאיננה גדלה מעבר ל-7200 בתים, וגודל מתאר התהליך קטן מ-1000 בתים 0x015fa878 esp 0x015fa3cb Process Descriptor 0x015fa000 current מערכות הפעלה - תרגול 3

  24. ניהול תהליכים בגרעין (6) • מצורת האחסון הנ"ל נובעת דרך פשוטה "לשלוף" את כתובת מתאר התהליך מתוך esp כאשר המעבד ב-kernel mode: לאפס את 13 הביטים הנמוכים של esp • בהתאם לדוגמה בשקף הקודם: esp = 0x15fa878 esp & 0xffffe000 = 0x15fa000 – כתובת מתאר התהליך • המאקרו current (קובץ גרעין include/asm-i386/current.h) משתמש בשיטה זו על מנת לאחסן את כתובת מתאר התהליך בערך מוחזר p: movl $0xffffe000, %ecx movl %esp, p andl %ecx, p מערכות הפעלה - תרגול 3

  25. רשימת התהליכים (1) ניהול תהליכים בגרעין • מתארי כל התהליכים מחוברים ברשימה מקושרת כפולה מעגלית הקרויה רשימת התהליכים (process list) באמצעות השדות prev_task ו-next_task • רשימה זו מקבילה ל"טבלת התהליכים" הקיימת במערכות ההפעלה אחרות • ראש הרשימה הוא המתאר של התהליך swapper prev_task next_task prev_task next_task prev_task next_task init_task מערכות הפעלה - תרגול 3

  26. רשימת התהליכים (2) ניהול תהליכים בגרעין • המאקרו SET_LINKS ו-REMOVE_LINKS (קובץ גרעין include/linux/sched.h) משמשים להוספה והסרה של מתאר תהליך ברשימת התהליכים • מטפלים גם ב"קשרי משפחה" בין תהליכים. פרטים בהמשך • המאקרו for_each_task (אותו קובץ גרעין) מאפשר לעבור על כל התהליכים ברשימה בסריקה דרך השדה next_task: #define for_each_task(p) for (p = &init_task; (p = p->next_task) != &init_task; ) מערכות הפעלה - תרגול 3

  27. מיפוי PID למתאר תהליך (1) ניהול תהליכים בגרעין • אמנם קריאות מערכת המתייחסות לתהליך מציינות את ה-pid של התהליך, אך הגרעין עובד עם מתאר התהליך • לפיכך, הוגדר בגרעין מנגנון המאתר את מתאר התהליך לפי ה-pid של התהליך • המנגנון מבוסס על hash-table בגודל PIDHASH_SZ (בד"כ 1024) כניסות • בדרך-כלל מספר התהליכים במערכת קטן בהרבה מ-32K ולכן אין צורך להחזיק כניסות עבור כל ה-pid האפשריים • התנגשויות בפונקצית ה-hash נפתרות על-ידי קישור מתארי התהליך, המתמפים לאותה כניסה בטבלה, ברשימה מקושרת כפולה דרך השדות pidhash_next ו-pidhash_pprev מערכות הפעלה - תרגול 3

  28. מיפוי PID למתאר התהליך (2) ניהול תהליכים בגרעין • הפונקציות hash_pid() ו-unhash_pid() מאפשרות להוסיף ולהסיר מתאר תהליך לטבלה • הפונקציה find_task_by_pid() מבצעת את איתור מתאר התהליך לפי ה-pid הנתון pidhash … 0 PID 199 PID 26799 199 … PID 26800 216 pidhash_next pidhash_pprev … 1023 מערכות הפעלה - תרגול 3

  29. ניהול קשרי משפחה בגרעין (1) ניהול תהליכים בגרעין • "קשרי המשפחה" בין תהליכים מיוצגים בגרעין באמצעות מצביעים בין מתארי תהליכים • מתאר תהליך אב מצביע למתאר תהליך הבן הצעיר ביותר שלו (שנוצר אחרון) באמצעות שדה p_cptr במתאר התהליך • מתאר תהליך מצביע למתאר תהליך האב שלו באמצעות השדה p_opptr • במתאר התהליך קיים שדה מצביע נוסף הקרוי p_pptr המצביע למתאר תהליך האב בפועל. ערך זה שונה מתהליך האב כאשר התהליך נמצא בריצה מבוקרת ע"י debugger או tracer • מתאר תהליך מצביע למתאר תהליך ה"אח הבוגר" (older sibling), כלומר מתאר התהליך שאביו יצר לפניו, באמצעות השדה p_osptr • מתאר תהליך מצביע למתאר תהליך ה"אח הצעיר" (younger sibling), כלומר מתאר התהליך שאביו יצר אחריו, באמצעות השדה p_ysptr מערכות הפעלה - תרגול 3

  30. ניהול קשרי משפחה בגרעין (2) ניהול תהליכים בגרעין • באמצעות "קשרי המשפחה" • תהליך יכול לאתר את אביו • למשל, עבור getppid() • תהליך יכול לאתר את בניו לפי סדר יצירתם • למשל, עבור wait() P0 p_(o)pptr p_ysptr p_osptr p_cptr P1 P2 P3 P4 מערכות הפעלה - תרגול 3

  31. רשימות מקושרות בגרעין (1) ניהול תהליכים בגרעין • לצורך ניהול תורים ומבני נתונים אחרים הגרעין משתמש ברשימות מקושרות כפולות מעגליות • הגדרת מבנה הרשימה בקובץ הגרעין include/linux/list.h • כל איבר ברשימה הוא מסוג list_t struct list_head { struct list_head *next, *prev; }; typedef struct list_head list_t; data structure 1 data structure 2 data structure 3 list_head next next next next prev prev prev prev מערכות הפעלה - תרגול 3

  32. רשימות מקושרות בגרעין (2) ניהול תהליכים בגרעין • האיברים ברשימה הם שדות המוכלים ברשומות מבני נתונים • מבני הנתונים המכילים את אברי הרשימה מקושרים זה לזה באמצעות הרשימה • הפעולות על הרשימה כוללות, בין השאר: • יצירת (ראש) הרשימה: LIST_HEAD • הוספת איבר במקום נתון (list_add) ובסוף הרשימה (list_add_tail) • הסרת איבר נתון (list_del) • בדיקה האם הרשימה ריקה (list_empty) • גישה לרשומה המכילה איבר נתון (list_entry) #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr) – (unsigned long)(&((type *)0)->member))) • לולאת מעבר על איברים ברשימה (list_for_each) מערכות הפעלה - תרגול 3

  33. הטווח הקצר (1) ניהול תהליכים בגרעין • מתארי התהליכים המוכנים לריצה ב-Linux (מצב TASK_RUNNING) נגישים מתוך מבנה נתונים הקרוי runqueue (קובץ גרעין kernel/sched.c) • לכל מעבד יש runqueue משלו • כל runqueue מכיל מספר תורים של מתארי תהליכים, אחד לכל עדיפות של תהליך • כל תור ממומש כרשימה מעגלית כפולה שתוארה קודם • השדה run_list במתאר התהליך הוא איבר הקישור ברשימה (מסוג list_head) מערכות הפעלה - תרגול 3

  34. הטווח הקצר (2) ניהול תהליכים בגרעין • הפונקציות enqueue_task() ו-dequeue_task() מכניסות ומוציאות [מתאר] תהליך ב-runqueue • הפונקציה wake_up_process() הופכת תהליך ממתין למוכן לריצה (TASK_RUNNING), מוסיפה את התהליך ל-runqueue באמצעות enqueue_task() ומסמנת צורך בהחלפת הקשר אם התהליך החדש מועדף לריצה על-פני האחרים מערכות הפעלה - תרגול 3

  35. הטווח הבינוני/ארוך (1) ניהול תהליכים בגרעין • תהליך שצריך להמתין לאירוע כלשהו לפני המשך ריצתו (TASK_(UN)INTERRUPTIBLE) נכנס לתור המתנה (wait queue) • כמו כן, התהליך יוצא מה-runqueue ומוותר על המעבד • כל תור המתנה משויך לאירוע או סוג אירוע כלשהו, כגון • פסיקת חומרה, למשל דיסק או שעון • התפנות משאב מערכת לשימוש. לדוגמה: ערוץ תקשורת שהתפנה וניתן לשלוח דרכו נתונים • אירועים אחרים כלשהם, כמו סיום תהליך • כאשר קורה האירוע אליו מקושר תור ההמתנה, מערכת ההפעלה "מעירה" תהליכים מתוך התור, כלומר מחזירה אותם למצב ריצה (TASK_RUNNING) מערכות הפעלה - תרגול 3

  36. הטווח הבינוני/ארוך (2) ניהול תהליכים בגרעין • תהליך ממתין בתור יכול להיות באחד משני מצבים: • exclusive (בלעדי) – כאשר האירוע המעורר קורה, מעירים אחד מהתהליכים שממתינים עם סימון "בלעדי". למשל: כאשר האירוע הוא שחרור של משאב שניתן לשימוש רק על-ידי תהליך יחיד ב-זמנית • non-execlusive (משותף) – כאשר האירוע המעורר קורה, מעירים את כל התהליכים שממתינים עם סימון "משותף". למשל: כאשר האירוע הוא פסיקת שעון שיכולה לסמן סוף המתנה עבור תהליכים שונים הממתינים למשך זמן קצוב • בדרך-כלל אין באותו תור המתנה ממתינים בלעדיים ומשותפים יחד מערכות הפעלה - תרגול 3

  37. הטווח הבינוני/ארוך (3) ניהול תהליכים בגרעין • תור המתנה ממומש כרשימה מקושרת כפולה מעגלית שתוארה קודם (קובץ גרעין include/linux/wait.h) struct __wait_queue_head { spinlock_t lock; struct list_head task_list; }; typedef __wait_queue_head wait_queue_head_t; • כל תהליך בתור מוצבע מאיבר ברשימה המוגדר כדלהלן: struct __wait_queue { unsigned int flags; struct task_struct *task; struct list_head task_list; }; typedef struct __wait_queue wait_queue_t; השדה lock מיועד להגן על התור מפני גישה במקביל על-ידי שני תהליכים או יותר השדה flags מציין האם ההמתנה היא exclusive (1) או non-exclusive (0) מערכות הפעלה - תרגול 3

  38. הטווח הבינוני/ארוך (4) ניהול תהליכים בגרעין • פונקציה להכנסת תהליך להמתנה בתור - sleep_on() void sleep_on(wait_queue_head_t *q) { unsigned long flags; wait_queue_t wait; wait.flags = 0; wait.task = current; current->state = TASK_UNINTERRUPTIBLE; add_wait_queue(q, &wait); schedule(); remove_wait_queue(q, &wait); } הפונקציות add_wait_queue[_exclusive]() ו-remove_wait_queue() מכניסות ומוציאות תהליך מהתור מערכות הפעלה - תרגול 3

  39. הטווח הבינוני/ארוך (5) ניהול תהליכים בגרעין • פונקציות נוספות מאפשרות הכנסת תהליך לתור כשהוא ממתין במצב interruptible ו/או כשהממתין בלעדי • במקביל, פונקציות המשמשות "להעיר" תהליכים: • wake_up מעירה את כל הממתינים המשותפים ואחד מהבלעדיים • גרסאות נוספות של wake_up: • להעיר מספר מוגבל של תהליכים ממתינים • להעיר רק ממתינים שהם interruptible • לבצע החלפת הקשר אם התהליך המועדף לריצה משתנה לאחר שמעירים תהליכים מערכות הפעלה - תרגול 3

More Related