Σήμα (υπολογιστές)

Στην επιστήμη της πληροφορικής, τα σήματα (signals) είναι μία περιορισμένη μορφή διαδιεργασιακής επικοινωνίας η οποία χρησιμοποιείται στο Unix, μα και σε άλλα λειτουργικά συστήματα τα οποία υπακούν στο πρότυπο POSIX. Πρόκειται για διακοπές λογισμικού που δρουν ως σινιάλα και μπορούν να αποστέλλονται σε μία διεργασία από κάποια άλλη ή από τον πυρήνα, αναγκάζοντάς την να τα χειριστεί ασύγχρονα μόλις τα λάβει και ακολούθως να επιστρέφει στην κανονική ροή εκτέλεσης. Κάθε σήμα διακρίνεται από έναν ακέραιο με τον οποίο είναι συσχετισμένο κάποιο συμβολικό όνομα (SIGxxxx). Το μοντέλο είναι το εξής: ένα πρόγραμμα στον κώδικά του δηλώνει ότι μία συνάρτηση είναι χειριστής ενός συγκεκριμένου σήματος (εγκατάσταση χειριστή). Όταν ληφθεί το σήμα αυτό κατά την εκτέλεση της αντίστοιχης διεργασίας, αυτομάτως η τελευταία διακόπτει ό,τι έκανε (εντολή Α) και εκτελεί τον χειριστή. Μόλις ο χειριστής επιστρέψει ο έλεγχος δίνεται ξανά στην εντολή Α. Ένας χειριστής εγκαθίσταται με την κλήση συστήματος sigaction() (αν δίνεται η ειδική τιμή SIG_IGN ως όρισμα στη sigaction() αντί για όνομα συνάρτησης, τότε το αντίστοιχο σήμα αγνοείται από τη διεργασία), ενώ με τις κλήσεις kill() ή sigqueue() το τρέχον πρόγραμμα αποστέλλει ένα συγκεκριμένο σήμα σε μία συγκεκριμένη διεργασία (η διαφορά τους είναι ότι η sigqueue(), μαζί με το σήμα, αποστέλλει και έναν επιπλέον ακέραιο με δεδομένα του προγραμματιστή). Σχεδόν για κάθε σήμα υπάρχει κάποιος προεπιλεγμένος χειριστής ο οποίος παρέχεται από το πρότυπο POSIX και δεν χρειάζεται να γραφεί ή να εγκατασταθεί χειροκίνητα (συνήθως επιφέρει τον τερματισμό της διεργασίας ή αγνοεί τελείως το σήμα)· για κάποια συγκεκριμένα σήματα μάλιστα δεν μπορεί να υποσκελιστεί από χειριστή του προγραμματιστή.

 Συνήθως μία διεργασία μπορεί να αποστείλει σήματα μόνο σε άλλες διεργασίες του ίδιου χρήστη, εκτός κι αν ανήκει στον λογαριασμό του διαχειριστή του συστήματος οπότε μπορεί να αποστείλει σήματα σε οποιαδήποτε άλλη διεργασία. Αν μία διεργασία δεν εκτελείται όταν ο πυρήνας τής παραδίδει κάποιο σήμα (π.χ. αν εκείνη τη στιγμή εκτελείται κάποια άλλη σε συνθήκες πολυδιεργασίας), τότε το σήμα αποθηκεύεται και της παραδίδεται μόλις λάβει τον έλεγχο του επεξεργαστή. Σε ορισμένες περιπτώσεις όμως η αποστολή σήματος προκαλεί άμεση θεματική εναλλαγή και εκτέλεση της διεργασίας-παραλήπτη, ώστε ο χειρισμός του σήματος να γίνει με πολύ μικρή καθυστέρηση. Αν μία διεργασία αρχίσει να χειρίζεται κάποιο σήμα διακόπτοντας έτσι την εκτέλεση κάποιας κλήσης συστήματος, τότε η τελευταία αποτυγχάνει και επιστρέφει τη συμβολική τιμή EINTR μετά τον τερματισμό του χειριστή. Στα περισσότερα λειτουργικά συστήματα είναι δυνατόν με χρήση της συμβολικής τιμής SA_RESTART στα ορίσματα της sigaction() να προσδιοριστεί ότι οι κλήσεις συστήματος οι οποίες διακόπτονται από τον αντίστοιχο χειριστό κατά τον χρόνο εκτέλεσης, θα επανεκκινούνται αυτομάτως αντί να αποτυγχάνουν. Σε ορισμένα συστήματα αυτή είναι η προεπιλεγμένη συμπεριφορά. Σημαντικό ζήτημα είναι η αναστολή παράδοσης σημάτων στην τρέχουσα διεργασία ώστε να μην μπορούν να εκτελεστούν οι αντίστοιχοι χειριστές σε χρονικές περιόδους που θα μπορούσαν να προξενήσουν προβλήματα. Αυτή η αναστολή ορίζεται από μία μάσκα μπλοκαρισμένων σημάτων η οποία τροποποιείται με την κλήση sigprocmask(), ενώ με την κλήση sigpending() μία διεργασία μπορεί κάθε στιγμή να ελέγξει ποια σήματα τής έχουν αποσταλεί αλλά δεν τα έχει παραλάβει επειδή τα έχει μπλοκάρει. Συνήθως είναι απαραίτητη η αναστολή παράδοσης όλων των σημάτων όσο εκτελείται ένας χειριστής ώστε να διασφαλιστεί η ομαλή λειτουργία του προγράμματος. Προκειμένου να μην καλείται χειροκίνητα η sigprocmask() μία φορά στην αρχή του χειριστή (όπου τίθεται η νέα μάσκα που περιλαμβάνει όλα τα σήματα) και μία φορά στο τέλος του (όπου επαναφέρεται η παλαιά μάσκα), παρέχεται η δυνατότητα ενσωμάτωσης της νέας μάσκας στον ίδιο τον χειριστή, μέσω κατάλληλων ορισμάτων της sigaction(), ώστε η αλλαγή της μάσκας να συμβαίνει αυτόματα μόλις ενεργοποιείται και μόλις επιστρέφει ο χειριστής. Τη στιγμή που αναιρείται η αναστολή παράδοσης ενός σήματος Α τότε, αν όντως εστάλη τουλάχιστον ένα σήμα Α κατά το χρονικό διάστημα της αναστολής στην τρέχουσα διεργασία, αμέσως παραδίδεται στην τελευταία ένα σήμα Α. Το πρότυπο POSIX παρέχει επίσης τις κλήσεις pause() και sigwait(), οι οποίες μπλοκάρουν την καλούσα διεργασία επ' αόριστον μέχρι αυτή να λάβει κάποιο σήμα (οποιοδήποτε με την pause() ή κάποιο συγκεκριμένο με τη sigwait()), την κλήση sleep(), η οποία μοιάζει με την pause() αλλά μπλοκάρει την καλούσα διεργασία μόνο για πεπερασμένο μέγιστο χρονικό διάστημα το οποίο της δίνεται ως όρισμα, και την οικογένεια κλήσεων sigXXXset() που επενεργούν σε δομές δεδομένων οι οποίες αναπαριστούν μάσκες σημάτων, προσθαφαιρώντας συγκεκριμένα σήματα σε αυτές ή ελέγχοντας ποια σήματα περιλαμβάνουν. Η πρότυπη βιβλιοθήκη της C παρέχει εξειδικευμένες δομές δεδομένων οι οποίες αναπαριστούν μάσκες σημάτων αλλά και κάποια από τα ορίσματα της sigaction(). Ενδιαφέροντα σήματα είναι τα παρακάτω: Ακολουθεί ένα παράδειγμα χειρισμού σημάτων σε γλώσσα προγραμματισμού C: Αρχιτεκτονική Υπολογιστών: Μια Δομημένη Προσέγγιση, Tanenbaum Andrew S., Εκδ. Κλειδάριθμος Σύγχρονα Λειτουργικά Συστήματα, Tanenbaum Andrew S., Εκδ. Κλειδάριθμος