fcntl#
מבצע פעולת בקרת קובץ של fcntl(2) על מטפל קובץ.
fcntl הוא הקישור הישיר של Perl לקריאת המערכת POSIX fcntl(2). הוא קורא או משנה מצב per-descriptor - מצב non-blocking, close-on-exec, נעילות רשומה מייעצות, דגלי descriptor - על־ידי הפעלת FUNCTION מול FILEHANDLE, כאשר SCALAR משמש כארגומנט קלט, כבופר פלט, או שניהם, בהתאם לאיזה FUNCTION מועבר.
קודי ה־FUNCTION אינם ליטרלים ברמת Perl; הם מאקרואים של מעבד הקדם של C שנחשפים על־ידי המודול Fcntl. יש לטעון אותו קודם, אחרת FUNCTION יהיה bareword לא־מוגדר:
use Fcntl;
תקציר#
use Fcntl;
fcntl FILEHANDLE, FUNCTION, SCALAR
my $flags = fcntl($fh, F_GETFL, 0);
fcntl($fh, F_SETFL, $flags | O_NONBLOCK);
מה מקבלים בחזרה#
בהצלחה, המספר השלם שהקרנל החזיר. כאשר אותו מספר שלם הוא 0, Perl מחליף במחרוזת דו־ערכית "0 but true" - אמת בהקשר בוליאני, מספרי 0 בהקשר מספרי, ופטור מהאזהרה Argument "..." isn't numeric. הדבר מאפשר לבדוק את התוצאה עם or die אפילו עבור פעולות שערך ההצלחה שלהן הוא תרתי משמע אפס:
fcntl($fh, F_SETFD, FD_CLOEXEC)
or die "F_SETFD: $!";
בכישלון, fcntl מחזיר undef וקובע את $! ל־errno הרלוונטי. אין צורך לעטוף את הערך המוחזר ב־defined - מוסכמת "0 but true" הופכת בדיקת אמת רגילה למספיקה.
עבור קודי FUNCTION שכותבים בחזרה דרך SCALAR (כגון F_GETLK), הבתים המעודכנים נוחתים בסקלר שהועבר; הערך המוחזר עדיין עוקב אחר הכלל לעיל.
כיצד נעשה שימוש ב־SCALAR#
SCALAR משחק שלושה תפקידים שונים בהתאם ל־FUNCTION:
מספר שלם של קלט. עבור קריאות שקובעות דגלים כמו
F_SETFDאוF_SETFL,SCALARהוא מסיכת הביטים המספרית להתקנה.מציין־מקום שמתעלמים ממנו. עבור קריאות שמשיגות דגלים כמו
F_GETFDאוF_GETFL, ה־SCALARאינו בשימוש על־ידי הקרנל; יש להעביר0על־פי המוסכמה.בופר struct לכניסה/יציאה. עבור קריאות לנעילת רשומה כמו
F_GETLK,F_SETLK, ו־F_SETLKW,SCALARחייב להכילstruct flockארוז - יש לבנות אותו עםpackלפני הקריאה, ועבורF_GETLKיש לפענח את הבתים המוחזרים עםunpackלאחר מכן.
כאשר SCALAR משמש כבופר פלט, יש לקבוע את גודלו מראש לפחות לאורך ה־struct שהקרנל יכתוב; סקלר בגודל לא־מספיק מורחב אוטומטית, אך קביעת גודל מראש הופכת את הכוונה לברורה.
מצב גלובלי שהוא נוגע בו#
דוגמאות#
הפיכת סוקט ל־non-blocking - השימוש הקנוני:
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
my $flags = fcntl($remote, F_GETFL, 0)
or die "F_GETFL: $!";
fcntl($remote, F_SETFL, $flags | O_NONBLOCK)
or die "F_SETFL: $!";
קביעת close-on-exec כך שה־descriptor לא יורש על־ידי תהליכי ילד דרך exec:
use Fcntl qw(F_SETFD FD_CLOEXEC);
fcntl($fh, F_SETFD, FD_CLOEXEC)
or die "F_SETFD: $!";
קריאת דגלי ה־descriptor הנוכחיים ובדיקת ביט:
use Fcntl qw(F_GETFD FD_CLOEXEC);
my $fd_flags = fcntl($fh, F_GETFD, 0);
defined $fd_flags or die "F_GETFD: $!";
if ($fd_flags & FD_CLOEXEC) {
# descriptor will close on exec
}
הצבת נעילת כתיבה מייעצת על הקובץ כולו. פריסת struct flock היא ספציפית לפלטפורמה; בלינוקס s s l l i מכסה את l_type l_whence l_start l_len l_pid:
use Fcntl qw(F_SETLK F_WRLCK SEEK_SET);
my $lock = pack('s s l l i', F_WRLCK, SEEK_SET, 0, 0, 0);
fcntl($fh, F_SETLK, $lock)
or die "lock refused: $!";
כיבוי דגל יחיד - מיסוך החוצה של O_NONBLOCK כדי להחזיר מטפל למצב blocking:
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
my $flags = fcntl($fh, F_GETFL, 0);
fcntl($fh, F_SETFL, $flags & ~O_NONBLOCK)
or die "F_SETFL: $!";
מקרי קצה#
שכחו
use Fcntl:F_GETFLוחבריו מנותחים כ־barewords ומוערכים כמטרד ברמת אזהרה תחתuse strict/use warnings, או למחרוזת"F_GETFL"אחרת - בכל מקרה הקריאה נכשלת עםEINVAL. יש לטעון תמיד אתFcntlקודם.ערך מוחזר
"0 but true": אין להשוות את הערך המוחזר עם== 0כבדיקת כישלון. יש להשתמש בבוליאני רגיל (or die) אוdefined- הראשון הוא המטבע.F_SETLKלעומתF_SETLKW:F_SETLKמחזירundefוקובע את$!ל־EAGAIN/EACCESכאשר תהליך אחר מחזיק נעילה מתנגשת.F_SETLKWחוסם עד שהנעילה ניתנת. יש לבחור במכוון; ערבוב ביניהם הוא המקור הרגיל לתקיעות.פלט
F_GETLK: בהצלחה, בתי ה־struct flockב־SCALARנדרסים במידע על הנעילה המתנגשת (אוl_type == F_UNLCKאם האזור פנוי). יש לבצעunpackחזרה עם אותה תבנית שאיתה בוצע pack.לא כל מערכת ממשת כל FUNCTION:
fcntlמעלה חריגה על מכונה שאינה ממשת אתfcntl(2)כלל. במערכות שכן, קודיFUNCTIONשאינם נתמכים נכשלים עםEINVALדרך$!. המודולFcntlמייצא רק קבועים שהפלטפורמה הנוכחית בעצם מגדירה.fcntlלעומתioctl: שניהם חולקים את מוסכמת עיבוד הארגומנטים והערך המוחזר, אך הם מכוונים לממשקי קרנל שונים. יש להשתמש ב־fcntlעבור דגלי descriptor ונעילות מייעצות; יש להשתמש ב־ioctlעבור קודי בקרה ספציפיים להתקן.fcntlלעומתflock:flockמשתמש בנעילותflock(2)בסגנון BSD לקובץ כולו, שבלינוקס פועלות יחד עם נעילות POSIX שלfcntlרק בדרכים מוגבלות. אם דרושה נעילת טווח־בתים או סמנטיקת POSIX (נעילה משוחררת בכלcloseשל הקובץ על־ידי התהליך הבעלים), יש להשתמש ב־fcntlעםF_SETLK; אחרתflockפשוט יותר.
הבדלים מ־upstream#
תואם מלא ל־upstream Perl 5.42.
ראו גם#
Fcntl- המודול שמייצא את הקבועיםF_*/O_*/FD_*/SEEK_*ש־fcntlמצפה להם; יש לבצעuseעליו תמיד קודםioctl- אותה מוסכמת קריאה וערך מוחזר כמוfcntl, אך עבור קודי בקרת התקן ולא דגלי בקרת קובץflock- נעילות מייעצות פשוטות יותר לקובץ כולו; יש להושיט יד אליו כאשר אין צורך בטווח־בתים או בסמנטיקת POSIXopen- פותח את מטפל הקובץ מלכתחילה; חלק מהדגלים ש־fcntlמתאים (למשלO_NONBLOCK,O_APPEND) גם ניתנים לקביעה בזמן הפתיחהsysopen- פתיחה ברמה נמוכה שלוקחת את אותם דגליO_*מ־Fcntl; יש להשתמש בו כאשר רוצים את הדגלים מוחלים אטומית ולא דרךfcntl(F_SETFL)עוקבpack/unpack- נדרשים לבניית ופענוח של בופר ה־struct flockשבו משתמשיםF_GETLK/F_SETLK