This question spans 2 stages — each part below is tagged with, and links to, the stage it belongs to.
תזכורות: • בכל הקצאה של מזהה קובץ חדש (file descriptor) נבחר המזהה הפנוי הקטן ביותר. • מתוך man pipe: int pipe(int pipefd[2]); The array pipefd is used to return two file descriptors referring to the ends of the pipe. pipefd[0] refers to the read end of the pipe. pipefd[1] refers to the write end of the pipe. If all file descriptors referring to the write end of a pipe have been closed, then an attempt to read() from the pipe will see end-of-file (read() will return 0). If all file descriptors referring to the read end of a pipe have been closed, then a write() will cause a SIGPIPE signal to be generated for the calling process. • מתוך man dup: int dup(int oldfd); The dup() system call creates a copy of the file descriptor oldfd, using the lowest-numbered unused file descriptor for the new descriptor. After a successful return, the old and new file descriptors may be used interchangeably. נתון קטע הקוד הבא: 1. // assume relevant #includes are all here 2. void transfer() { // transfer chars from STDIN to STDOUT 3. char c; 4. ssize_t ret = 1; 5. while ((read(0, &c, 1) > 0) && ret > 0) 6. ret = write(1, &c, 1); 7. exit(0); 8. } 9. int main() { 10. int my_pipe[2]; 11. close(0); 12. printf("Hi"); 13. pipe(my_pipe); 14. if (fork() == 0) { // son process 15. close(my_pipe[1]); 16. transfer(); 17. } 18. close(1); 19. dup(my_pipe[1]); 20. printf("Bye"); 21. return 0; 22. }
Full original question text (raw OCR)
שאלה 4 - תקשורת בין תהליכים (25 נק') תזכורות: • בכל הקצאה של מזהה קובץ חדש (file descriptor) נבחר המזהה הפנוי הקטן ביותר. • מתוך man pipe: int pipe(int pipefd[2]); The array pipefd is used to return two file descriptors referring to the ends of the pipe. pipefd[0] refers to the read end of the pipe. pipefd[1] refers to the write end of the pipe. If all file descriptors referring to the write end of a pipe have been closed, then an attempt to read() from the pipe will see end-of-file (read() will return 0). If all file descriptors referring to the read end of a pipe have been closed, then a write() will cause a SIGPIPE signal to be generated for the calling process. • מתוך man dup: int dup(int oldfd); The dup() system call creates a copy of the file descriptor oldfd, using the lowest-numbered unused file descriptor for the new descriptor. After a successful return, the old and new file descriptors may be used interchangeably. נתון קטע הקוד הבא: 1. // assume relevant #includes are all here 2. void transfer() { // transfer chars from STDIN to STDOUT 3. char c; 4. ssize_t ret = 1; 5. while ((read(0, &c, 1) > 0) && ret > 0) 6. ret = write(1, &c, 1); 7. exit(0); 8. } 9. int main() { 10. int my_pipe[2]; 11. close(0); 12. printf("Hi"); 13. pipe(my_pipe); 14. if (fork() == 0) { // son process 15. close(my_pipe[1]); 16. transfer(); 17. } 18. close(1); 19. dup(my_pipe[1]); 20. printf("Bye"); 21. return 0; 22. }
להלן דיאגרמה של טבלת הקבצים הפתוחים ברגע הכניסה לפונקציה main: [Diagram] (5 נק') השלימו את כל ההצבעות החסרות באיור הבא, בהינתן שתהליך האב סיים לבצע את שורה 19 ותהליך הבן סיים לבצע את שורה 15: [Diagram]
fork/exec address-space semanticslibc syscall wrapper caching pitfallsSignal delivery and handler timing(5 נק') מה יודפס למסך בסיום ריצת שני התהליכים? (הניחו שקריאות המערכת אינן נכשלות) a. Hi b. Bye c. HiBye d. לא יודפס כלום e. התהליך לא יסתיים לעולם f. לא ניתן לדעת, תלוי בתזמון של התהליכים נימוק:
libc syscall wrapper caching pitfallsreview:T2·22(5 נק') מה יודפס למסך כאשר תהליך האב יסיים לרוץ? (הניחו שקריאות המערכת אינן נכשלות) רמז: שרטטו דיאגרמה של טבלאות הקבצים כפי שראיתם בסעיף 1. a. Hi b. Bye c. HiBye d. ByeHi e. לא יודפס כלום f. לא ניתן לדעת, תלוי בתזמון של התהליכים נימוק:
libc syscall wrapper caching pitfallsreview:T2·22סטטיק וּקֶרְן-אֶל שמעו שסטודנטים רבים בקורס עבדו במהלך יום הסטודנט על תרגיל הבית שנדחה ונהנו יותר מאשר בהופעות. בתגובה נזעמת, סטטיק התחבר לשרת הפקולטה והריץ את התוכנית הנ"ל N פעמים באופן סדרתי (דוגמה ב-bash, כאשר a . out הוא קובץ ההרצה של התכנית הנ"ל): >> for i in {1..N}; do ./a.out; done (5 נק') מה המספר המינימלי של סיגנלים שצריך לשלוח באמצעות kill על מנת להרוג את כל התהליכים החדשים שסטטיק יצר? a. 0 b. 1 c. N d. N/2 e. 2N f. לא ניתן לדעת, תלוי בתזמון של התהליכים נימוק:
Signal delivery and handler timing(5 נק') מה תהיה התשובה עבור הסעיף הקודם אם נסיר את שורות 6-7 מהקוד? a. 0 b. 1 c. N d. N/2 e. 2N f. לא ניתן לדעת, תלוי בתזמון של התהליכים נימוק:
fork/exec address-space semanticslibc syscall wrapper caching pitfallsSignal delivery and handler timing
The exam question — original PDF
pages 11, 12, 13, 14, 15Exactly as it appears on the exam paper.
Built from these components
Ordered basic → advanced. Master the earlier ones first.
Review the material
Read these before you answer — each verified slide teaches a component this question tests, and nothing from an unrelated topic is included. Tutorial slides show the actual slide image.
inodes & *stat syscalls • lstat(2) – Exactly the same as stat(2) if applied to a hard link – But if applied to a symlink, would return the information of this symlink (not to the target of the symlink) – In this case, POSIX says that the only fields within the stat structure that you can portably use are: • st_mode which will specify that the file is a symlink • st_size symlink content length (= length of target filepath) – The value of the rest of the fields could be valid, but it is not specified by POSIX – Notably, it is not specified if a symlink has a corresponding inode • Will be discussed shortly OS (234123) - files 34
אחרי fork()parentint main() { int x = 0; pid_t p = fork(); if (p == 0) { x = 1; } else { x = 2; }}sonint main() { int x = 0; pid_t p = fork(); if (p == 0) { x = 1; } else { x = 2; }}מערכות הפעלה - תרגול 210
קריאות המערכת getpid(), getppid()pid_t getpid();קריאת מערכת המחזירה לתהליך הקורא את ה-pid של עצמו.pid_t getppid();קריאת מערכת המחזירה את ה-PID של תהליך האב של התהליך הקורא.שאלה: מה המשמעות של getppid() == 1 עבור תהליך משתמש טיפוסי?תשובה: תהליך האב הוא init. קורה למשל אם תהליך הבן יתום.מערכות הפעלה - תרגול 222
קריאת המערכת kill#include <sys/types.h>#include <signal.h>int kill(pid_t pid, int sig);פעולה: שולחת את הסיגנל שמספרו sig לתהליך המזוהה ע"י pid.אם הערך של sigהוא 0, אז הפעולה רק בודקת שהתהליך pid קיים, מבלי לשלוח signal (שימושי לבדיקת תקפות pid).ערך מוחזר:0 בהצלחה-1 בכישלון (למשל, אם אין תהליך בעל מזהה pid)מערכות הפעלה - תרגול 38
העברת סיגנלים בשני שלביםרישום – מערכת ההפעלה רושמת ב-PCB של תהליך היעד שיש לו סיגנל ממתין (pending signal).הרישום מתבצע במערך בינארי בין 31 ביטים, ולכן לכל תהליך יכול להיות לכל היותר סיגנל ממתין אחד מכל מספר.טיפול – בכל פעם שהתהליך חוזר ממצב גרעין למצב משתמש, מערכת ההפעלה בודקת אם יש סיגנלים ממתינים ומטפלת בהם.בסיום הטיפול בסיגנל, מערכת ההפעלה תאפס את הביט המתאים במערך. במידה ויש מספר סיגנלים ממתינים, סדר הטיפול מתחילת המערך לסופו.מערכות הפעלה - תרגול 39
FD (file descriptors)כל פעולות קלט/פלט של תהליך בלינוקס מבוצעות דרך "קבצים":קבצים "רגילים" לאחסון מידע (/usr/file.txt) נמצאים בדיסק.התקני חומרה גם כן מיוצגים כקבצים, אבל נמצאים בזיכרון.למשל, העכברים המחוברים למחשב מיוצגים כ- /dev/input/mouseN .גם ערוצי תקשורת כמו pipes מיוצגים ע"י קבצים שנמצאים בזיכרון.הקשר בין תהליך לבין קובץ שהוא ניגש אליו נשמר, ברמת המשתמש, ע"י מספר שלם שנקרא file descriptor (FD).לדוגמה: קריאת המערכת open() מחזירה FD.המשתמש מעביר את ה-FD לקריאות מערכת כמו read(), write() כדי לקרוא ולכתוב לקובץ.מערכות הפעלה - תרגול 320
שחרור file objectשאלה: מי מבצע את שחרור הזיכרון של file object? מתי ניתן לשחררו? ייתכנו מצבים בהם תהליכים שונים מצביעים לאותו file object, לכן שחרור ה-file object יכול להתבצע רק לאחר ביצוע close() מכל התהליכים החולקים את אותו ה-file object. זכרו של-file object יש מונה (f_count) הסופר את כמות התהליכים המצביעים עליו בכל רגע נתון. המונה קטן באחד עם כל פעולת close() על האובייקט. כאשר המונה מתאפס, ה-file object ישוחרר.מערכות הפעלה - תרגול 342
יצירת חוט חדשפרמטרים:thread – מצביע למקום בו יאוחסן מזהה החוט החדש במקרה של סיום הפונקציה בהצלחה.attr – מאפיינים המתארים את תכונות החוט החדש, כגון האם החוט הוא חוט גרעין או חוט משתמש, האם ניתן לבצע לו join, כלומר להמתין לסיומו, וכו'. בד"כ נספק ערך NULL המציין חוט ברירת המחדל של המערכת, שניתן להמתין לסיומו.void* (*start_routine)(void*) מצביע לפונקציה שתהווה את קוד החוט. הערך המוחזר מפונקציה זו במקרה של סיומה הטבעי הינו ערך הסיום של החוט.arg – פרמטר שיסופק לפונקציה עם הפעלתה.מערכות הפעלה - תרגול 714
משתנה תנאי (condition variable)משתנה תנאי הוא אובייקט סנכרון המאפשר לחוט לצאת להמתנה בתוך קטע קריטי.כלומר, לפנות את המעבד ולצאת לתור המתנה.ההמתנה תתבצע עד לקיום תנאי כלשהו.ההמתנה מאפשרת לאכוף סדר בביצוע של החוטים. שימוש תכנותי נכון במשתני תנאי מחייב להגדיר גם:משתנה מצב – החוט עובר להמתנה או חוזר מהמתנה בהתאם לערכו של משתנה המצב.מנעול mutex – מבטיח לנו אטומיות והגנה על הקטע הקריטי.מערכות הפעלה - תרגול 86
סכימה כללית למשתני תנאיcond_t c; // should be initializedmutex_t m; // should be initializedint state_var = 0;החוט הממתין לאירוע יקרא ל:while (!condition_holds(state_var)) cond_wait(&c, &m);החוט שמסמן לחוטים הממתינים להמשיך יקרא ל:if (condition_holds(state_var)) cond_signal(&c);מערכות הפעלה - תרגול 87מדוע cond_wait() מקבלתגם את המנעול?
המתנה על משתני תנאיint pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);פעולה: משחררת את המנעול ומעבירה את החוט להמתין על משתנה התנאי באופן אטומי (ראינו קודם מדוע זה הכרחי).החוט הממתין חייב להחזיק במנעול mutex לפני הקריאה.בחזרה מהמתנה על משתנה התנאי, החוט עובר להמתין על המנעול. החוט יחזור מהקריאה ל-pthread_cond_wait() רק לאחר שינעל מחדש את ה-mutex.ערך מוחזר: הפעולה תמיד מצליחה ומחזירה 0.11מערכות הפעלה - תרגול 8
שחרור חוטים ממתיניםint pthread_cond_signal(pthread_cond_t *cond); משחררת את אחד החוטים הממתינים (הגינות לא מובטחת).int pthread_cond_broadcast(pthread_cond_t *cond);משחררת את כל החוטים הממתינים.כל החוטים מפסיקים להמתין על משתנה התנאי ועוברים להמתין על המנעול. החוטים יחזרו לפעילות בזה אחר זה (בסדר כלשהו, לאו דווקא הוגן) לאחר שינעלו מחדש את ה-mutex.שימו לב: אם אין אף חוט שממתין באותו רגע על משתנה התנאי cond, הפעולות חסרות השפעה (הסיגנל הולך לאיבוד ואינו נזכר הלאה).ערך מוחזר: הפונקציות תמיד מצליחות ומחזירות 0.מערכות הפעלה - תרגול 812
בלינוקס יש שני סוגי קישורים (links)soft / symbolic linkln -s src dstקישור סימבולי הוא קובץ חדש עם inode נפרד מזה של הקובץ המקורי.כתיבה דרך הקישור כותבת לקובץ אליו הוא מצביע.מחיקת הקישור (באמצעות הפקודה rm) לא תמחק את הקובץ המוצבע.אפשר ליצור קישורים סימבוליים גם לקובץ שלא קיים.hard linkln src dstקישור קשיח הוא שם נרדף לקובץ המקורי כי הוא מצביע ישירות ל-inode של הקובץ המקורי.כתיבה דרך הקישור כותבת לקובץ אליו הוא מצביע.מחיקת הקישור תקטין את מונה הקישורים של הקובץ (כפי שנשמר ב-inode).הקובץ יימחק מהדיסק רק כאשר כל ה-hard links אליו יימחקו.מערכות הפעלה - תרגול 1213
>> rm /A/helloמערכות הפעלה - תרגול 1219inode #2type=dirdatanameinode #A5B7inode #5type=dirdatanameinode #…………inode #13type=soft_linkdatainode #7type=dirdatanameinode #soft13……data block/A/helloקישור "שבור"!dangling link
The exam text, the skills it tests, and the exact slides are already in context.