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) με το πλήρες λεξιλόγιο σημαιών, χωρίς να χρειάζεται η ωμή syscall

  • pipe - ο σωστός τρόπος για να δημιουργήσετε σωλήνα· αποφεύγει το πρόβλημα του άκρου εγγραφής της SYS_pipe()

  • pack - κατασκευάστε τις δυαδικές δομές (struct timeval, struct stat κ.λπ.) που αναμένουν οι syscalls σε ορίσματα δείκτη

  • unpack - αποκωδικοποιήστε τις δυαδικές δομές που μια syscall γράφει στον ενταμιευτή σας