IPC System V Προγραμματισμός II 1 lalis@inf.uth.gr
Διαδιεργασιακή επικοινωνία System V 3 είδη «αντικειμένων» (μηχανισμών) επικοινωνίας ουρές μηνυμάτων (message queues): msg κοινόχρηστες περιοχές μνήμης (shared memory): shm σηματοφόροι (semaphores): sem Διατηρούνται στην μνήμη του λειτουργικού χάνονται σε κλείσιμο/επανεκκίνηση του Η/Υ Δεν προσπελάζονται μέσω περιγραφέων αρχείου δεν υποστηρίζουν τις open, read, write, close Υπάρχουν ξεχωριστές εντολές για την εμφάνιση και διαγραφή των αντικειμένων επικοινωνίας ipcs (στο πνεύμα της ls), ipcrm (στο πνεύμα της rm) Προγραμματισμός II 2 lalis@inf.uth.gr
Λειτουργίες αντικειμένων επικοινωνίας Γενικές λειτουργίες: <Χ>get: δημιουργία/ανεύρεση αντικειμένου επικοινωνίας (<Χ> είναι msg, shm ή sem) <Χ>ctl: έλεγχος/καταστροφή αντικειμένου επικοινωνίας (<Χ> είναι msg, shm ή sem) Επιπλέον ειδικές λειτουργίες, ανά είδος αντικειμένου: msgsnd/msgrcv (αποστολή/παραλαβή μηνύματος) shmat/shmdt (προσάρτηση/αποδέσμευση μνήμης) semop (χειρισμός σηματοφόρων) Προγραμματισμός II 3 lalis@inf.uth.gr
Αναγνωριστικά και κλειδιά Κάθε αντικείμενο επικοινωνίας λαμβάνει (από το λειτουργικό) ένα μοναδικό αναγνωριστικό int Το αναγνωριστικό έχει μόνο προσωρινή ισχύ και ακυρώνεται σε κάθε επανεκκίνηση του Η/Υ Ένα αντικείμενο επικοινωνίας μπορεί να συσχετιστεί με ένα κλειδί, ώστε να μπορεί να «εντοπιστεί» από άλλα προγράμματα αντίστοιχο με το «όνομα» ενός αρχείου/αγωγού/υποδοχέα Τα προγράμματα που επιθυμούν να επικοινωνήσουν μέσω ενός αντικειμένου επικοινωνίας πρέπει να γνωρίζουν είτε το κλειδί είτε το αναγνωριστικό του Προγραμματισμός II 4 lalis@inf.uth.gr
Παραγωγή (μοναδικών) κλειδιών key_t ftok(const char *path, int id); Παράγει και επιστρέφει ένα (μοναδικό) κλειδί Το όνομα path αντιστοιχεί σε ένα ισχύον μονοπάτι στον χώρο ονομάτων του συστήματος αρχείων Χρησιμοποιείται μόνο το least significant byte του id Η μοναδικότητα ενός κλειδιού προκύπτει από τον συνδυασμό ονόματος/μονοπατιού και αριθμού Το πρόγραμμα πρέπει να έχει πρόσβαση στο αντίστοιχο αρχείο/κατάλογο Προγραμματισμός II 5 lalis@inf.uth.gr
Άδειες χρήσης αντικειμένων επικοινωνίας Ξεχωριστό σύστημα αδειών από το σύστημα αρχείων Οι άδειες καθορίζονται με τα «συνηθισμένα» 9 bits ανάγνωση, γράψιμο και εκτέλεση για ιδιοκτήτη, ομάδα, άλλους Υποστηρίζονται ξεχωριστές άδειες για τον δημιουργό του αντικειμένου επικοινωνίας μπορεί να είναι διαφορετικός από τον ιδιοκτήτη Οι άδειες καθορίζονται μέσω <Χ>get (μόνο όταν δημιουργείται ένα νέο αντικείμενο επικοινωνίας) Μπορεί να διαβαστούν/αλλαχθούν μέσω <Χ>ctl Προγραμματισμός II 6 lalis@inf.uth.gr
Ουρές Μηνυμάτων στο System V (Message Queues) Προγραμματισμός II 7 lalis@inf.uth.gr
Ουρά μηνυμάτων Αποθήκη μηνυμάτων στην μνήμη του λειτουργικού Περιορισμένος αριθμός / όγκος μηνυμάτων μπορεί να αλλάξει μέσω msgctl Το περιεχόμενο ενός μηνύματος είναι μια σειρά από bytes (την σημασία των οποίων γνωρίζει το πρόγραμμα που το δημιούργησε) Κάθε μήνυμα είναι ξεχωριστό από τα υπόλοιπα Πολλές διεργασίες μπορεί να χρησιμοποιούν την ίδια ουρά μηνυμάτων ταυτόχρονα Προγραμματισμός II 8 lalis@inf.uth.gr
P1 P2 P3 P4 msg4 msg3 msg2 msg1 Προγραμματισμός ΙΙ 9 lalis@inf.uth.gr
Δημιουργία/ανεύρεση ουράς μηνυμάτων int msgget(key_t key, int flags); Δημιουργεί/βρίσκει την ουρά μηνυμάτων με κλειδί key, και επιστρέφει το αναγνωριστικό της Βασικές επιλογές flags IPC_CREAT: δημιουργεί την ουρά μηνυμάτων IPC_EXCL: αποτυχία αν η ουρά ήδη υπάρχει άδειες, χρησιμοποιώντας τις ίδιες τιμές όπως στην open Αν το key είναι IPC_PRIVATE δημιουργείται μια ανώνυμη/ιδιωτική ουρά μηνυμάτων δεν μπορεί να βρεθεί μέσω msgget Προγραμματισμός II 10 lalis@inf.uth.gr
Έλεγχος ουράς μηνυμάτων int msgctl(int msqid, int cmd, struct msqid_ds *data); H cmd προσδιορίζει την ζητούμενη λειτουργία IPC_RMID: καταστροφή ουράς μηνυμάτων IPC_STAT: ανάκτηση πληροφοριών για την ουρά IPC_SET: καθορισμός ιδιοτήτων της ουράς Η αποθήκευση πληροφοριών και ο καθορισμός των επιθυμητών ιδιοτήτων γίνεται μέσω ειδικής δομής Η χωρητικότητα της ουράς μπορεί να ελεγχθεί ή/και να επαναπροσδιοριστεί μέσω της msgctl Αν η ουρά καταστραφεί, οι επόμενες κλήσεις πάνω στο αναγνωριστικό της ουράς αποτυγχάνουν, με την errno να λαμβάνει την τιμή EIDRM Προγραμματισμός II 11 lalis@inf.uth.gr
Δομή μηνυμάτων struct msg { long mtype; // convention! // data/payload }; Η δομή είναι ενδεικτική (δεν ορίζεται πουθενά) Τα πρώτα sizeof(long) bytes ερμηνεύονται από το λειτουργικό ως ο τύπος του μηνύματος Ο τύπος ενός μηνύματος πρέπει να είναι θετικός Μπορεί να γίνει παραλαβή μηνυμάτων ανάλογα με τον τύπο τους βλέπε παρακάτω Προγραμματισμός II 12 lalis@inf.uth.gr
Αποστολή μηνύματος int msgsnd(int msqid, void *msgp, size_t msize, int flags); Τοποθετεί το μήνυμα msgp στην ουρά msqid Το μέγεθος του μηνύματος επιπλέον των bytes που αντιστοιχούν στον τύπο, δίνεται μέσω msize Μπλοκάρει αν δεν υπάρχει διαθέσιμος χώρος Αποφυγή μπλοκαρίσματος: IPC_NOWAIT στα flags αν δεν υπάρχει χώρος, η κλήση επιστρέφει άμεσα με τιμή αποτυχίας και την errno ίση με EAGAIN Προγραμματισμός II 13 lalis@inf.uth.gr
Παραλαβή μηνύματος ssize_t msgrcv(int msqid, void *msgp, size_t msize,long mtype,int flags); Απομακρύνει ένα μήνυμα από την ουρά msqid το αποθηκεύει (έως msize bytes) στο msgp, και επιστέφει το πόσα bytes αποθηκεύτηκαν αποτυγχάνει αν το μήνυμα δεν χωράει (errno ίσο E2BIG) εκτός αν στα flags συμπεριληφθεί MSG_NOERROR οπότε αντιγράφονται msize bytes ενώ το υπόλοιπο χάνεται Το μήνυμα επιλέγεται με βάση το mtype 0: το πρώτο μήνυμα στην ουρά >0: το πρώτο μήνυμα με αυτό το τύπο (ή το πρώτο μήνυμα με διαφορετικό τύπο, αν η flags περιέχει το MSG_EXCEPT) <0: το πρώτο μήνυμα με τον μικρότερο τύπο < mtype Μπλοκάρει αν δεν υπάρχει κατάλληλο μήνυμα εκτός αν στα flags συμπεριληφθεί IPC_NOWAIT, οπότε η κλήση αποτυγχάνει (errno ίσο με ENOMSG) Προγραμματισμός II 14 lalis@inf.uth.gr
(1) P1 P2 msg queue PING... (2) P1 msg queue P2 PONG... Προγραμματισμός ΙΙ 15 lalis@inf.uth.gr
struct msg { long type; char data[maxdata]; }; int main (int argc, char *argv[] ) { int mqid; struct msg m; mqid = msgget(ipc_private,s_irwxu); if (!fork()) { msgrcv(mqid,&m,maxdata,ping,0); printf("child got: %s\n",m.data); m.type=pong; strcpy(m.data,"pong from child"); msgsnd(mqid,&m,strlen(m.data)+1,0); return(0); } } m.type=ping; strcpy(m.data,"ping from parent"); msgsnd(mqid,&m,strlen(m.data)+1,0); msgrcv(mqid,&m,maxdata,pong,0); printf("parent got: %s\n",m.data); msgctl(mqid,ipc_rmid,null); return(0); Προγραμματισμός ΙΙΙ 16 lalis@inf.uth.gr
client queue (1) client server server queue ADD_REQ... (2) client client queue ADD_RES... server queue server Προγραμματισμός ΙΙ 17 lalis@inf.uth.gr
#define MSGQ_KEY 1234 // instead of using ftok #define REQ 1 #define RSP 2 #define REQ_SIZE (sizeof(struct request)-sizeof(long)) #define RSP_SIZE (sizeof(struct response)-sizeof(long)) struct request { long type; // REQ int mqid; // message queue id to use for reply int a,b; // arguments }; struct response { long type; // RSP int res; // result }; Προγραμματισμός ΙΙΙ 18 lalis@inf.uth.gr
int main (int argc, char *argv[] ) { int mqid; struct request req; struct response rsp={0}; } mqid = msgget(msgq_key,ipc_creat S_IRWXU); do { msgrcv(mqid,&req,req_size,0,0); if (req.type!= REQ) { continue; } // ignore rsp.type = RSP; rsp.res = req.a + req.b; msgsnd(req.mqid,&rsp,rsp_size,0); } while (rsp.res!= -1); msgctl(mqid,ipc_rmid,null); return(0); int main (int argc, char *argv[] ) { int mqid1,mqid2; struct request req; struct response rsp; } mqid1 = msgget(msgq_key,0); mqid2 = msgget(ipc_private,s_irwxu); req.type = REQ; req.mqid = mqid2; req.a = atoi(argv[1]); req.b = atoi(argv[2]); msgsnd(mqid1,&req,req_size,0); msgrcv(mqid2,&rsp,rsp_size,rsp,0); msgctl(mqid2,ipc_rmid,null); return(0); Προγραμματισμός ΙΙΙ 19 lalis@inf.uth.gr