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 שלכם