Presentation is loading. Please wait.

Presentation is loading. Please wait.

מערכות הפעלה תרגול 3 – תהליכים ב-Linux (1). מערכות הפעלה - תרגול 32 (c) ארז חדד 2003 תוכן התרגול מבוא לתהליכים ב-Linux API לעבודה עם תהליכים מבוא לניהול.

Similar presentations


Presentation on theme: "מערכות הפעלה תרגול 3 – תהליכים ב-Linux (1). מערכות הפעלה - תרגול 32 (c) ארז חדד 2003 תוכן התרגול מבוא לתהליכים ב-Linux API לעבודה עם תהליכים מבוא לניהול."— Presentation transcript:

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

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

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

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

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

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

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

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

9 מערכות הפעלה - תרגול 39 (c) ארז חדד 2003 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

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

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

12 מערכות הפעלה - תרגול 312 (c) ארז חדד 2003 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);

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

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

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

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

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

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

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

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

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

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

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

24 מערכות הפעלה - תרגול 324 (c) ארז חדד 2003 ניהול תהליכים בגרעין (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

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

26 מערכות הפעלה - תרגול 326 (c) ארז חדד 2003 רשימת התהליכים (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; ) ניהול תהליכים בגרעין

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

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

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

30 מערכות הפעלה - תרגול 330 (c) ארז חדד 2003 ניהול קשרי משפחה בגרעין (2) באמצעות "קשרי המשפחה"  תהליך יכול לאתר את אביו למשל, עבור getppid()  תהליך יכול לאתר את בניו לפי סדר יצירתם למשל, עבור wait() P0P0 P3P3 P2P2 P1P1 P4P4 p_(o)pptr p_ysptr p_osptr p_cptr ניהול תהליכים בגרעין

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

32 מערכות הפעלה - תרגול 332 (c) ארז חדד 2003 רשימות מקושרות בגרעין (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) ניהול תהליכים בגרעין

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

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

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

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

37 מערכות הפעלה - תרגול 337 (c) ארז חדד 2003 הטווח הבינוני/ארוך (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) ניהול תהליכים בגרעין

38 מערכות הפעלה - תרגול 338 (c) ארז חדד 2003 הטווח הבינוני/ארוך (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() מכניסות ומוציאות תהליך מהתור ניהול תהליכים בגרעין

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


Download ppt "מערכות הפעלה תרגול 3 – תהליכים ב-Linux (1). מערכות הפעלה - תרגול 32 (c) ארז חדד 2003 תוכן התרגול מבוא לתהליכים ב-Linux API לעבודה עם תהליכים מבוא לניהול."

Similar presentations


Ads by Google