קלט/פלט · נתונים באורך קבוע

syscall#

הפעלת קריאת מערכת גולמית לפי מספר הקרנל שלה, תוך העברת הארגומנטים הנותרים כ־int או כמצביע ל־buffer של מחרוזת.

syscall היא דלת המילוט עבור קריאות מערכת־הפעלה שאינן עטופות בשאר השפה. הארגומנט הראשון הוא מספר ה־syscall - בלינוקס, הערך של SYS_<name> מ־syscall.ph. כל ארגומנט נותר מועבר או כמספר שלם (אם Perl כבר חושב עליו כמספרי) או כמצביע ל־buffer של המחרוזת של הסקלר. היא מחזירה את מה שהקרנל מחזיר. בכישלון היא מחזירה -1 וקובעת את $!.

תקציר#

syscall NUMBER, LIST

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

מה שהקרנל החזיר. ערכי הצלחה הם ספציפיים ל־syscall - לעיתים קרובות ספירת בתים, file descriptor, או 0. כישלון הוא -1 עם $! שנקבע לערך errno.

חלק מה־syscalls (lseek, read על pipe ב־EOF עם שגיאות, ptrace) יכולים להחזיר -1 באופן לגיטימי בהצלחה. כדי להבחין ביניהם לבין כישלונות, יש לנקות את $! לפני הקריאה:

$! = 0;
my $r = syscall(SYS_lseek(), fileno($fh), 0, 1);
die "lseek: $!" if $r == -1 && $! != 0;

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

  • $! - נקבע כאשר הקרנל מחזיר -1. אינו נוגע בהצלחה.

כללי העברת ארגומנטים#

כל ארגומנט ב־LIST נבחן בזמן הקריאה:

  • ארגומנט מספרי (מספר ליטרלי, או סקלר ששימש בהקשר מספרי) - מועבר כ־C int.

  • ארגומנט לא־מספרי - ה־buffer של המחרוזת של הסקלר מועבר במצביע. אחריותכם להאריך מראש את ה־buffer כדי להכיל כל נתון שהקרנל עשוי לכתוב. buffer קצר מדי הוא באג של שיבוש זיכרון, לא שגיאת Perl.

  • מחרוזת קריאה־בלבד (ליטרל, מחרוזת __DATA__, כל מה ש־Perl מסרב לכתוב דרכו) - נדחה, מכיוון ש־syscall חייב להניח שמצביע מחרוזת כלשהו עשוי להיכתב דרכו.

  • מספר שלם המאוחסן כמחרוזת (לדוגמה ערך שנקרא מקובץ שמעולם לא שימש אריתמטית) - עשוי להיות מועבר כמצביע ולא כ־int. יש לאלץ פרשנות מספרית על־ידי הוספת 0:

    syscall(SYS_write(), 0 + $fd, $buf, length $buf);
    

עד 14 ארגומנטים נתמכים לאחר מספר ה־syscall.

דוגמאות#

כתיבת buffer ל־STDOUT באמצעות ה־syscall הגולמי write(2):

require 'syscall.ph';
my $s = "hi there\n";
syscall(SYS_write(), fileno(STDOUT), $s, length $s);

הארכה מראש של buffer לפני קריאה:

require 'syscall.ph';
my $buf = "\0" x 4096;                # 4 KiB writable buffer
my $n = syscall(SYS_read(), fileno($fh), $buf, 4096);
die "read: $!" if $n == -1;
substr($buf, $n) = '';                # trim to actual bytes read

קריאה ל־gettid(2) כדי לקבל את ה־id של thread הקרנל (אין עטיפת libc ב־glibc ישן יותר):

require 'syscall.ph';
my $tid = syscall(SYS_gettid());

הבחנה בין החזרת -1 לגיטימית לבין כישלון אמיתי:

$! = 0;
my $off = syscall(SYS_lseek(), fileno($fh), 0, 1);   # SEEK_CUR
if ($off == -1 && $! != 0) {
    die "lseek failed: $!";
}

אילוץ מספר שלם שעבר stringify להיות מועבר כ־int:

my $fd = read_config("fd");           # returns "3"
syscall(SYS_close(), 0 + $fd);        # without "0 +" it'd pass a pointer

מקרי קצה#

  • syscall.ph חסר: require 'syscall.ph' נכשל אלא אם h2ph הורץ מול ה־headers של המערכת. בלעדיו הקבועים SYS_* אינם מוגדרים והקריאות הופכות למספרי קסם המתוחזקים ידנית.

  • ארגומנט קריאה־בלבד: העברת ליטרל מחרוזת או סקלר קריאה־בלבד אחר עושה croak עם Modification of a read-only value. יש להעתיק ללקסיקלי קודם: my $s = "literal"; syscall(..., $s, ...).

  • Buffer קצר מדי: הקרנל יכתוב בשמחה מעבר לסוף ה־buffer של סקלר אם שיקרתם לגבי האורך. זה משבש את ה־heap של Perl. תמיד יש להאריך מראש עם $buf = "\0" x $n או vec($buf, $n-1, 8) = 0 לפני הקריאה, ולעולם לא להעביר length $buf גדול מהקיבולת בפועל.

  • תקרת מספר ארגומנטים: 14 ארגומנטים לאחר NUMBER. Syscalls שלוקחים יותר (נדיר) אינם נגישים דרך syscall.

  • SYS_pipe() בלינוקס: ה־syscall הגולמי מחזיר את ה־fd של הצד הקורא אבל אינו נותן לכם handle על ה־fd של הצד הכותב. יש להשתמש ב־pipe במקום, החושף את שניהם.

  • ערכי 64־ביט בפלטפורמות 32־ביט: חלק מה־syscalls לוקחים ארגומנטים של 64־ביט (offsets, גדלים) שאינם נכנסים ב־int של Perl ב־builds של 32־ביט. אין דרך ניידת להעבירם דרך syscall - יש להשתמש בעטיפה ייעודית (Fcntl::lseek, sysseek וכדומה) או בקישור CPAN.

  • לא מיושם: בפלטפורמות ללא נקודת כניסה syscall(2) (או כאשר ה־build בוצע ללא תמיכה), syscall מעלה The syscall function is unimplemented.

  • הפסקת אות: syscall שהופסק על־ידי אות מחזיר -1 עם $! שנקבע ל־EINTR. syscall אינו מתחיל מחדש אוטומטית - יש לנסות שוב בקוד המשתמש אם נדרש.

הבדלים מ־upstream#

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

ראו גם#

  • syswrite - כתיבה עוקפת־buffer דרך מטפל קובץ של Perl; כמעט תמיד מה שרוצים במקום syscall(SYS_write(), ...)

  • sysread - קריאה עוקפת־buffer; מצטרף ל־syswrite ומנהל את ה־buffer עבורכם

  • sysopen - open(2) עם אוצר המלים המלא של דגלים, ללא צורך ב־syscall הגולמי

  • pipe - הדרך הנכונה ליצור pipe; נמנעת מבעיית הצד־הכותב של SYS_pipe()

  • pack - בניית ה־structs הבינאריים (struct timeval, struct stat וכדומה) ש־syscalls מצפים להם בארגומנטים של מצביעים

  • unpack - פענוח ה־structs הבינאריים ש־syscall כותב לתוך ה־buffer שלכם