I/O · Δεδομένα σταθερού μήκους
syscall#
Επικαλείται ωμή κλήση συστήματος με βάση τον αριθμό πυρήνα της, περνώντας τα υπόλοιπα ορίσματα ως int ή ως δείκτη σε ενταμιευτή συμβολοσειράς.
Η syscall είναι η διέξοδος για κλήσεις λειτουργικού συστήματος που η υπόλοιπη γλώσσα δεν περιτυλίγει. Το πρώτο όρισμα είναι ο αριθμός syscall - σε Linux, η τιμή του SYS_<name> από το syscall.ph. Κάθε υπόλοιπο όρισμα περνά είτε ως ακέραιος (αν η Perl το θεωρεί ήδη αριθμητικό) είτε ως δείκτης στον ενταμιευτή συμβολοσειράς του βαθμωτού. Επιστρέφει ό,τι επιστρέφει ο πυρήνας. Σε αποτυχία επιστρέφει -1 και θέτει το $!.
Σύνοψη#
syscall NUMBER, LIST
Τι επιστρέφεται#
Ό,τι επέστρεψε ο πυρήνας. Οι τιμές επιτυχίας είναι ειδικές ανά syscall - συχνά αριθμός bytes, περιγραφέας αρχείου ή 0. Η αποτυχία είναι -1 με το $! τεθειμένο στην τιμή errno.
Ορισμένες syscalls (lseek, read σε σωλήνα στο EOF με σφάλματα, ptrace) μπορούν νόμιμα να επιστρέψουν -1 σε επιτυχία. Για να τις διακρίνετε από αποτυχίες, καθαρίστε το $! πριν την κλήση:
$! = 0;
my $r = syscall(SYS_lseek(), fileno($fh), 0, 1);
die "lseek: $!" if $r == -1 && $! != 0;
Καθολική κατάσταση που επηρεάζει#
$!- τίθεται όταν ο πυρήνας επιστρέφει-1. Δεν επηρεάζεται σε επιτυχία.
Κανόνες περάσματος ορισμάτων#
Κάθε όρισμα στη LIST επιθεωρείται κατά τον χρόνο κλήσης:
Αριθμητικό όρισμα (κυριολεκτικός αριθμός ή βαθμωτό που έχει χρησιμοποιηθεί σε αριθμητικό περιβάλλον) - περνά ως C
int.Μη αριθμητικό όρισμα - ο ενταμιευτής συμβολοσειράς του βαθμωτού περνά με δείκτη. Είστε υπεύθυνοι να επεκτείνετε εκ των προτέρων τον ενταμιευτή ώστε να χωρά όσα δεδομένα μπορεί να γράψει ο πυρήνας. Ένας πολύ κοντός ενταμιευτής είναι σφάλμα αλλοίωσης μνήμης, όχι σφάλμα Perl.
Συμβολοσειρά μόνο για ανάγνωση (κυριολεκτικό, συμβολοσειρά από
__DATA__, οτιδήποτε η Perl αρνείται να γράψει διαμέσου του) - απορρίπτεται, επειδή ηsyscallπρέπει να υποθέσει ότι κάθε δείκτης συμβολοσειράς μπορεί να γραφτεί διαμέσου.Ακέραιος αποθηκευμένος ως συμβολοσειρά (π.χ. τιμή διαβασμένη από αρχείο που δεν χρησιμοποιήθηκε ποτέ αριθμητικά) - μπορεί να περαστεί ως δείκτης αντί για ακέραιος. Εξαναγκάστε την αριθμητική ερμηνεία προσθέτοντας
0:syscall(SYS_write(), 0 + $fd, $buf, length $buf);
Υποστηρίζονται έως 14 ορίσματα μετά τον αριθμό syscall.
Παραδείγματα#
Γράψτε έναν ενταμιευτή στο STDOUT χρησιμοποιώντας την ωμή syscall write(2):
require 'syscall.ph';
my $s = "hi there\n";
syscall(SYS_write(), fileno(STDOUT), $s, length $s);
Προεκτείνετε έναν ενταμιευτή πριν μια ανάγνωση:
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 του πυρήνα (δεν υπάρχει wrapper 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: $!";
}
Εξαναγκάστε έναν ακέραιο που έχει μετατραπεί σε συμβολοσειρά να περαστεί ως 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_*είναι αόριστες και οι κλήσεις γίνονται χειρωνακτικά συντηρούμενοι μαγικοί αριθμοί.Όρισμα μόνο για ανάγνωση: το πέρασμα κυριολεκτικού συμβολοσειράς ή άλλου βαθμωτού μόνο για ανάγνωση πεθαίνει με
Modification of a read-only value. Αντιγράψτε πρώτα σε λεξιλογικό:my $s = "literal"; syscall(..., $s, ...).Ενταμιευτής πολύ κοντός: ο πυρήνας θα γράψει ευχαρίστως πέρα από το τέλος του ενταμιευτή ενός βαθμωτού αν είπατε ψέματα για το μήκος. Αυτό αλλοιώνει το heap της Perl. Προεπεκτείνετε πάντα με
$buf = "\0" x $nήvec($buf, $n-1, 8) = 0πριν την κλήση, και μην περνάτε ποτέlength $bufμεγαλύτερο από την πραγματική χωρητικότητα.Ανώτατο όριο πλήθους ορισμάτων: 14 ορίσματα μετά τον
NUMBER. Syscalls που δέχονται περισσότερα (σπάνια) δεν είναι προσπελάσιμες μέσω τηςsyscall.Η
SYS_pipe()σε Linux: η ωμή syscall επιστρέφει το fd του άκρου ανάγνωσης αλλά δεν σας δίνει handle στο fd του άκρου εγγραφής. Χρησιμοποιήστε αντί γι” αυτό τηνpipe, που εκθέτει και τα δύο.Τιμές 64-bit σε πλατφόρμες 32-bit: ορισμένες syscalls δέχονται ορίσματα 64-bit (offsets, μεγέθη) που δεν χωρούν σε ένα Perl
intσε builds 32-bit. Δεν υπάρχει φορητός τρόπος να τα περάσετε μέσω τηςsyscall- χρησιμοποιήστε ειδικό wrapper (Fcntl::lseek,sysseekκ.λπ.) ή binding από CPAN.Μη υλοποιημένη: σε πλατφόρμες χωρίς σημείο εισόδου
syscall(2)(ή όταν χτίστηκε χωρίς υποστήριξη), ηsyscallεγείρειThe syscall function is unimplemented.Διακοπή από σήμα: μια syscall που διακόπτεται από σήμα επιστρέφει
-1με το$!τεθειμένο σεEINTR. Ηsyscallδεν επανεκκινεί αυτόματα - ξαναδοκιμάστε σε επίπεδο Perl αν χρειάζεται.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42.
Δείτε επίσης#
syswrite- εγγραφή με παράκαμψη ενταμιευτή μέσω filehandle της Perl· σχεδόν πάντα αυτό που θέλετε αντί γιαsyscall(SYS_write(), ...)sysread- ανάγνωση με παράκαμψη ενταμιευτή· συνδυάζεται με τηsyswriteκαι χειρίζεται τη διαχείριση ενταμιευτή για εσάςsysopen-open(2)με το πλήρες λεξιλόγιο σημαιών, χωρίς να χρειάζεται η ωμή syscallpipe- ο σωστός τρόπος για να δημιουργήσετε σωλήνα· αποφεύγει το πρόβλημα του άκρου εγγραφής τηςSYS_pipe()pack- κατασκευάστε τις δυαδικές δομές (struct timeval,struct statκ.λπ.) που αναμένουν οι syscalls σε ορίσματα δείκτηunpack- αποκωδικοποιήστε τις δυαδικές δομές που μια syscall γράφει στον ενταμιευτή σας