יפו – המכללה האקדמית תל אביב – מערכות הפעלה 2# תרגיל בית מספר ~1~
Transcription
יפו – המכללה האקדמית תל אביב – מערכות הפעלה 2# תרגיל בית מספר ~1~
מערכות הפעלה – המכללה האקדמית תל אביב – יפו סמסטר א ,תשע"ה מרצה :כרמי מרימוביץ .מתרגל :צבי מלמד תרגיל בית מספר #2 הוראות כלליות בתרגיל הזה שתי שאלות: .1תכנית משתמש ב LINUXשמשתמשת בסמפורים ובזיכרון משותף .2מימוש סמפורים ב XV6 -וכתיבת תכנית בדיקה הגשה עד יום שני .5/1/15לכל מי שמתכנן לבקש הארכות – מועד זה כבר כולל הארכות... הוראות ההגשה המפורטות נמצאות באתר המעבדה. הסביבה הקובעת להרצת התרגילים: עבור לינוקס :סביבת Linux-ubuntu/VMWARE of the lab עבור :XV6סביבת BOCHS /CYGWINבמעבדה. כלומר ...אתם יכולים לפתח ולפתור את התרגילים בסביבה הנוחה לכם .אבל ,לפני ההגשה ,חובתכם לוודא שהתרגילים רצים בסביבה הפורמלית-סטנדרטית. ~~1 שאלה - #1תכנית PS – Prime-Semiprime הערה מקדימה :ידוע מה זה מספר ראשוני .prime numberאולי קצת פחות ידוע מה זה – semiprime number זהו מספר שמתקבל ממכפלה של שני מספרים ראשוניים. עליכם לכתוב זוג תכניות בלינוקס – לתכנית אחת נקרא ( pspקיצור של ) prime-SemiPrimeוהתכנית השנייה factorשפועלות באופן הבא. התכנית psp תחילה תהליך האב מייצר NO_SONSבנים .לאחר מכן ,תהליך האב קורא זוגות מספרים מתוך הקלט הסטנדרטי עד ( EOFהניחו שהקלט מכיל מספר זוגי של מספרים) .את המספרים שהאב קורא הוא שם במערך הציקלי ( num_arrayזוג מספרים בכל פעם) .לאחר מכן (כלומר לאחר )EOFהאב מוסיף למערך num_arrאפסים במספר כפול ממספר הבנים (כלומר סה"כ NUM_SONS * 2אפסים .האב ממתין לבנים ומסתיים. מטרתם של תהליכי הבנים עובדים באופן הבא .מטרתם "לשלוף" בכל פעם זוג מספרים מהמערך . .num_array לכל מספר שנשלף התהליך מחשב את המספר הראשוני הבא (גדול או שווה למספר שקרא) .כלומר ,הוא מחשב זוג מספרים ראשוניים .לאחר מכן הוא מכפיל את שני המספרים הראשוניים ,ואת הסמי-פריים הזה הוא כותב למערך ציקלי אחר ,בשם .sp_arrayכאשר בן קורא שני אפסים ,הוא מסתיים( .למעשה ,מספיק לבדוק שהוא נתקל באפס אחד בלבד ,אבל מכיוון שההכנסה וההוצאה מהמערך הם בזוגות ,משתמשים כאן בשני אפסים. התכנית factor התכנית מורכבת מתהליך בודד .התהליך קורא ("שולף" ,מוציא) מספר מהמערך ,sp_arrayמחשב את שני הגורמים של המספר ומדפיס אותם בפורמט זהה לפורמט של הפקודה factorבלינוקס (קיימת פקודה כזאת). הערות והנחיות נוספות: א. ב. ג. ד. ה. ו. ז. עליכם להשתמש בזיכרון משותף עבור המערכים הציקליים והמצביעים שקשורים בהם. שמות קבצי המקור שלכם יהיו . psp.c, factor.c :כמו כן ,יהיו לכם שני קבצים נוספים shared.c , shared.h שבהם יש הגדרות של קבועים ,מבנים ,פרוטוטייפים (בקובץ )shared.hומימוש של הפונקציות .הכוונה היא שבקבצים האלו יהיה כל מה שמשותף לשתי התכניות .יש למנוע כפילויות של קוד ככל שניתן. כל גישה למערך הציקלי (כתיבת נתון או שליפתו) מחייבת המתנה של 0.2שניות (השתמשו בפונקציה .)usleepכתיבה או שליפה של זוג מספרים (המערך )num_arrayמצריכה רק השהיה אחת .כל גישה למערך ( sp_arrayכתיבה או שליפה של מספר בודד) גם היא מצריכה השהיה אחת. יש לסנכרן את הגישה למערכים באמצעות סמפורים .מומלץ להשתמש ב named-semphoreשל POSIXכפי שראינו במעבדה .#9 קבועי התכנית : #define NO_SONS 3 // number of children process in psp program #define NO_NUM_ARR 8 // number of entries in num_array. // of course, number of pairs is half of that #define NO_SP_ARR 3 // number of entries in sp_array. #define U_SLEEP 200000 // micro-sec of delay. בתרגיל זה ,אין חשיבות ליעילות האלגוריתמים בחיפוש המספר הראשוני הבא או מציאת הגורמים של הסמיפריים( .כמובן ...במידה סבירה ...לולאות FORזה סביר .מי שיצליח לפתח אלגוריתם אקספוננציאלי זה לא סביר.)... הניחו שהקלט תקין ,מכיל רק מספרים חיוביים ,והמספרים שתקבלו לא יגרמו לחריגות כלשהן .בקיצור הטיפוס ( unsigned intאו )intיספק את צרכינו. ~~2 המלצות oהפרידו בין חגיגות .וודאו שהפונקציה (או פונקציות) שמטפלות במערך ציקלי עובדות היטב בנפרד מהזיכרון המשותף. oמומלץ להשתמש ב structעבור כל אחד מהמבנים הציקליים .הוא יכיל הן את המערך והן את המשתנים עבור גודלו והאינדקס. oבקריאות לפונקציות )( shm_openו mmap -אפשר להשתמש בדגלים הבאים: ;)shm_open(<name>, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG ;)mmap(NULL, <size>, <protection flags for read & write>, MAP_SHARED, <fd>, 0 ~~3 XV6 מימוש סמפורים ב- #2 שאלה וכן לכתוב תכנית משתמש שבודקת,שמוגדר להלןAPI עליכם לממש קריאות מערכת שממשות סמפורים על פי ה . עליכם לתעד את אופן מימוש הסמפורים ואת תכנית המשתמש שכתבתם.ומדגימה את השימוש בסמפורים :פרוטוטייפ הפונקציות int int int int int sem_open(char *name, int create, int init); sem_close(int sd); sem_wait(int sd); sem_trywait(int sd); sem_signal(int sd); :להלן תיאור ההתנהגות הדרושה מכל אחת מהפונקציות int sem_open(char *name, int create, int init); a) name - the name of the semaphore. This is a system wide name. The max length is 6. b) create – indicates if a new semaphore should be created o 1 means that a new semaphore should be created if a semaphore with this name does not exist in the system. In this case, the newly created semaphore gets the value init as it’s initial value. However, if such a semaphore exists in the system, then the ‘create’ and ‘init’ are ignored. o 0 means, don’t create a new semaphore. c) If create==0, and there isn’t such a semaphore in the system – a failure return code of -1 is returned. d) If create==0, and there is already such a semaphore the function returns sd (semaphore descriptor) which is the lowest available index in the process semaphore array. This works similar to the way that open file works. e) if create==1, sd will be returned as described in the previous bullet, i.e. the lowest available number in the semaphore array. Of course, this entry points to the semaphore that already existed in the system prior to this call, or to the one which was just created. f) init – the initial value in case a new semaphore is created. It should be non-negative. g) A kernel constant NOSEM limits the number of open semaphores per process, similar to the NOFILE. Of course, if the call might result in exceeding NOSEM (per this process), the call fails and returns -1. h) A kernel constant NSEM limits the total number of active semaphores in the system. This is similar to NFILE. int sem_close(int sd); a) This call closes an open semaphore. Error code of -1 is returned if sd is index of non-valid entry in the process semaphore table. b) If this is the last reference to the semaphore, then the semaphore is destroyed. (refer to the similar behavior of file close(). ~4~ int sem_wait(int sd); This is standard wait operation of semaphores. a) This call decrements the value of the semaphore, provided it does not become negative. If this is not possible, the process is suspended. b) The process is resumed when the decrement is possible. int sem_trywait(int sd); This call tries to decrement the value of the semaphore, provided it does not become negative. If this is possible, the call returns 0 (success). If this is not possible, the call returns -1 (failure), but the process is NOT suspended. int sem_signal(int sd); This is standard ‘signal’ (or ‘post’) operation of semaphores. a) The value of the semaphore is incremented. b) wakeup other process who might be waiting on this semaphore. Suggestions Don’t invent the wheel, and don’t invent the semaphore. Refer to handling of files (ofile and ftable) to get ideas on ways to implement things. Add a global variable stable to the system, defined as follows: struct { struct spinlock gslock; //global semaphore lock struct { struct spinlock sslock; // single semaphore lock ..... ..... } sem[NSEM]; } stable; Use gslock for sem_open and sem_close. Use sslock for sem_wait, sem_trywait and sem_signal. Consider the fork() – child should inherit all opened semaphores from the parent. Consider the implications of exit(). !!בהצלחה ~5~