SysV IPC

semget#

יצירה או חיפוש של מערכת סמפורים של System V והחזרת המזהה שלה.

semget היא נקודת הכניסה ל־API של סמפורי SysV. היא עוטפת את קריאת המערכת semget(2): בהינתן KEY מספרי שנותן שם למערכת, מספר הסמפורים NSEMS במערכת, ומילת FLAGS המשלבת ביטי הרשאה עם דגלי יצירה, הקרנל מחזיר או את ה־id של מערכת קיימת תואמת, או, אם IPC_CREAT ב־FLAGS, יוצר מערכת חדשה ומחזיר את ה־id שלה. ה־id המוחזר הוא ה־handle שכל קריאת סמפור אחרת (semop, semctl) מצפה לו.

תקציר#

semget KEY, NSEMS, FLAGS

מה מקבלים בחזרה#

מזהה מערכת הסמפורים (מספר שלם אי־שלילי) בהצלחה, או undef בכישלון עם $! שנקבע ל־errno מהקריאה הבסיסית semget(2). ה־id אינו file descriptor - זהו handle של SysV IPC ברמת הקרנל ששורד מעבר לתהליך שלכם ונמשך עד שמוסר במפורש עם semctl($id, 0, IPC_RMID, 0).

use IPC::SysV qw(IPC_CREAT IPC_PRIVATE);

my $semid = semget(IPC_PRIVATE, 3, IPC_CREAT | 0600)
    // die "semget: $!";

מצב גלובלי שהוא נוגע בו#

  • $! - נקבע לערך errno מ־semget(2) בכישלון (EACCES, EEXIST, ENOENT, ENOSPC, EINVAL, ENOMEM).

הארגומנט KEY#

KEY הוא מספר שלם הנותן שם למערכת הסמפורים ברמת־המערכת. שלוש מוסכמות חשובות:

  • IPC_PRIVATE (מיובא מ־IPC::SysV) - הקרנל מקצה מפתח טרי שלא בשימוש על־ידי שום מערכת אחרת. ה־id המתקבל ידוע רק לתהליך הזה ולמי שהוא מעביר אליו את ה־id, בדרך־כלל ילדים לאחר fork. יש להשתמש בזה כאשר המערכת היא פרט מימוש של עץ תהליכים אחד.

  • ליטרל מספר שלם קבוע - כל תהליך משתף־פעולה מקודד באופן קשיח את אותו מספר. שביר על־פני תוכניות שאינן קשורות אשר עשויות לבחור באותו מספר שלם.

  • מפתח שנגזר מ־ftok(3) - IPC::SysV::ftok($path, $proj_id) הופך נתיב מערכת קבצים בתוספת בית פרויקט למפתח מספרי. המתכון הסטנדרטי לתהליכים שאינם קשורים הזקוקים להסכים על מפתח ללא קידוד קשיח של מספר קסם.

הארגומנט FLAGS#

FLAGS משלב ביטי הרשאה (9 ביטים נמוכים, כמו mode של chmod: 0600, 0660, 0666) עם דגלי יצירה מ־IPC::SysV:

  • IPC_CREAT - יצירת המערכת אם היא אינה קיימת כבר. ללא דגל זה, semget רק מחפש מערכת קיימת עם המפתח הנתון.

  • IPC_CREAT | IPC_EXCL - יצירת המערכת, אבל כישלון עם EEXIST אם אחת כבר קיימת עבור KEY. המקבילה של SysV ל־O_CREAT | O_EXCL ב־open.

ביטי הרשאה נבדקים על־ידי הקרנל בכל קריאה עוקבת של semop ו־semctl מול ה־uid/gid של התהליך המבצע.

דוגמאות#

יצירת מערכת פרטית של שלושה סמפורים השמישים על־ידי תהליך זה וילדיו:

use IPC::SysV qw(IPC_PRIVATE IPC_CREAT);
my $semid = semget(IPC_PRIVATE, 3, IPC_CREAT | 0600)
    // die "semget: $!";

חיפוש מערכת קיימת בעלת שם מבלי ליצור אותה. NSEMS חייב להתאים לגודל שעמו המערכת נוצרה, או יכול להיות 0 אם לא אכפת:

use IPC::SysV qw(ftok);
my $key   = ftok("/var/run/myapp.pid", ord('M'));
my $semid = semget($key, 0, 0) // die "no set for key $key: $!";

אידיום יצירה־או־פתיחה - לנסות יצירה בלעדית, ולחזור לחיפוש. התהליך הראשון שעובר מאתחל את המערכת; מאוחרים יותר רק מתחברים:

use IPC::SysV qw(ftok IPC_CREAT IPC_EXCL);

my $key = ftok("/var/run/myapp.pid", ord('M'));
my $semid = semget($key, 4, IPC_CREAT | IPC_EXCL | 0660);
if (defined $semid) {
    # We created it - initialise every semaphore to 1.
    semctl($semid, 0, SETALL, pack("s!*", (1) x 4))
        or die "SETALL: $!";
} else {
    $semid = semget($key, 4, 0) // die "semget lookup: $!";
}

הסרת מערכת בסיום השימוש בה. מערכות SysV דולפות מעבר ליציאת תהליך - שום דבר לא מנקה אותן עבורכם:

use IPC::SysV qw(IPC_RMID);
semctl($semid, 0, IPC_RMID, 0) or warn "semctl RMID: $!";

מקרי קצה#

  • NSEMS בחיפוש: בעת חיפוש מערכת קיימת (ללא IPC_CREAT), NSEMS של 0 משמעו ״כל גודל״; ערך חיובי חייב להיות קטן או שווה לגודל בפועל של המערכת אחרת semget נכשל עם EINVAL.

  • IPC_PRIVATE עדיין מציית ל־FLAGS: ביטי הרשאה חלים. מערכת שנוצרה עם 0400 היא קריאה־בלבד אפילו לתהליך היוצר עבור קריאות semop שמשנות אותה.

  • מגבלות קרנל: semget יכול להיכשל עם ENOSPC כאשר מגבלת מערכות הסמפורים ברמת־המערכת נגמרת, או EINVAL כאשר NSEMS חורג מהמקסימום לכל־מערכת. ראו ipcs -sl למגבלות הנוכחיות בלינוקס.

  • Leaked sets: a set persists until IPC_RMID or reboot. Long-running daemons that forget to remove their sets accumulate them; ipcs -s lists the survivors, ipcrm -s $id removes one.

  • Key collisions: two unrelated programs picking the same hard-coded KEY will see each other’s set - hence the ftok(3) idiom.

  • אינו מטפל קובץ: $semid הוא מספר שלם, לא מטפל. אין להעבירו ל־close, fcntl, או כל פעולת מטפל קובץ.

  • Forks יורשים ids, לא בעלות: ילד רואה את אותו ערך $semid כמו ההורה ויכול להשתמש בו, אבל המערכת עצמה בבעלות ה־uid שיצר אותה, לא של תהליך מסוים.

  • הקשר מספרי: ה־id הוא מספר שלם פשוט, בטוח להדפסה, השוואה ושמירה בקובץ עבור תהליך אחר שיאסוף.

הבדלים מ־upstream#

תואם מלא ל־upstream Perl 5.42.

ראו גם#

  • semop - ביצוע פעולות wait/signal על המערכת שמוחזרת על־ידי semget

  • semctl - פעולות בקרה על המערכת: אתחול ערכים (SETALL, SETVAL), קריאתם (GETALL, GETVAL), והסרת המערכת (IPC_RMID)

  • msgget - המקבילה של תור־הודעות, אותן מוסכמות KEY, FLAGS

  • shmget - המקבילה של זיכרון משותף, אותן מוסכמות KEY, FLAGS

  • IPC::SysV - מייבא את IPC_CREAT, IPC_EXCL, IPC_PRIVATE, IPC_RMID, SETALL, GETALL, ואת עוזר ftok

  • IPC::Semaphore - עטיפת עצם סביב ה־built-ins הגולמיים של sem* כאשר מעדיפים לא לארוז structs ביד