IPC: Cozi de mesaje

O coadă de mesaje este o zonă în care pot fi adăugate mesaje de către un proces, de unde mai apoi pot fi extrase de către acelaşi proces sau de către un alt proces. Mesajele sunt identificate printr-un tip şi un conţinut. Scrierea şi citirea mesajelor nu se face după regula FIFO, procesul cititor putând extrage din coadă un mesaj de un anumit tip.

Crearea cozilor de mesaje

Funcţia sistem pentru crearea de cozi de mesaje este msgget. Semnătura funcţiei este:

     #include <sys/types.h>
     #include <sys/ipc.h>
     #include <sys/msg.h>
 
     int
     msgget(key_t key, int msgflg);

Pagina man asociată funcţiei msgget este aceasta.

Argument key reprezintă un întreg pozitiv pe baza căruia va fi generat un ID unic pentru coada de mesaje construită. Dacă valoarea cheii este IPC_PRIVATEA atunci coada de mesaje construită va putea fi accesată doar de către procesul creator al cozii şi de către fii acestuia (se spune despre coadă că este privată).

Argumentul msgflag poate să conţină flag-uri cum ar fi IPC_CREAT sau IPC_EXCL. Dacă falg-ul IPC_EXCL este setat şi o coadă cu cheia key există deja în sistem, atunci funcţia va returna mesaj de eroare. Dacă falgul IPC_CREAT este setat atunci funcţia construieşte o nouă structură de tip coadă de mesaje sau returnează ID-ul unei cozi existente construită cu aceiaşi cheie în cazul în care flagul IPC_EXCL nu a fost setat.

Tot în cadrul argumentului msgflag sunt setate şi drepturile de acces asupra cozii de forma 0xyz. Unde 0 specifică faptul că numărul este în baza opt, x specifică drepturile pentru utilizator, y specifică drepturile pentru grupul din care face parte utilizatorul şi z drepturile pentru restul utilizatorilor (similar cu modul în care sunt stabilite drepturile pentru fişierele standard Linux).

O secvenţă de cod care demonstrează modul în care se construieşte o coadă de mesaje este:

      #include <stdio.h>     /* standard I/O routines.            */
      #include <sys/types.h> /* standard system data types.       */
      #include <sys/ipc.h>   /* common system V IPC structures.   */
      #include <sys/msg.h>   /* message-queue specific functions. */
      ...
      int queue_id = msgget(101, 0660|IPC_CREAT); */
      if (queue_id == -1) {
          perror("msgget error");
          exit(1);
      }
      ...

Adaugarea mesajelor in coada

Înainte de a adăuga mesaje în coadă trebuie să ştim care este formatul mesajelor. În cadrul IPC este definită structura msgbuf care precizează structura mesajelor:

    struct msgbuf {
        long mtype;    
        char mtext[1];  
    };

Atributul mtype specifică tipul mesajului şi acesta trebuie să fie un întreg pozitiv. Al doilea atribut, mtext, este un vector de caractere ce va memora conţinutul efectiv al mesajului.

Nu suntem limitaţi la această structură de mesaje. Dacă dorim să transmitem mesaje cu o altă structură putem defini propria structură. De exemplu:

    struct mymsgbuf {
        long mtype;      
       char mtext[256];  
    };

Singurul atribut pe care trebuie să îl conţină în mod obligatoriu structura este mtype de tip long care specifică tipul mesajului.

Odată stabilită structura mesajelor care vor fi scrise în coadă putem scrie mesaje folosind funcţia msgsnd. Semnătura funcţie este:

     #include <sys/types.h>
     #include <sys/ipc.h>
     #include <sys/msg.h>
 
     int
     msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg);

Pagina man asociată funcţie msgget este aceasta.

Unde argumentul msgid reprezinţă id-ul cozii de mesaje returnat de funcţia msgget, argumentul msgp reprezintă un pointer la mesajul ce va fiscris, argumentul msgsz reprezintă dimensiunea efectivă a mesajului ce va fi scris (fără tipul mesajului) iar argumentul msgflg reprezintă un flag care specifică comportamentul funcţiei msgsnd atunci când se încearcă scrirea unnui mesaj într-o codă plină. Dacă flag-ul IPC_NOWAIT este setat şi coada este plină atunci funcţia returnează mesaj de eroare. Dacă flag-ul nu este setat funcţia blochează procesul apelant până când mesajul poate fi scris în coadă.

Secvenţa următoare exemplifică transmiterea într-o coadă a unui mesaj de tip definit mai sus:

    struct mymsgbuf msg;
    char* text=”un mesaj”;
    ...
    msg.mtype = 1;
    strcpy(msg.mtext,text);
    msgsnd(msgid,&msg,strlen(text),IPC_NOWAIT)l
    ...

Citirea mesajelor din coada

Pentru a extrage un mesaj din coada de mesaje se foloseşte funcţia msgrcv. Semnătura funcţiei este:

     #include <sys/types.h>
     #include <sys/ipc.h>
     #include <sys/msg.h>
 
     int
     msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

Pagina man asociată funcţiei msgget este aceasta.

Argumentul msgp este un pointer către o structură prealocată în care se va salva mesajul citit, argumentul msgsz este dimensiunea maximă a mesajului ce va fi citit, asrgumentul msgtyp este tipul mesajului ce va fi citit. Tipul mesajului poate fi:

  • 0 – caz in care primul mesaj din coadă va fi returnat;
  • Un întreg pozitiv – caz în care un mesaj de tipul respectiv va fi returnat (în cazul în care flagul msgflg este setat corespunzător);
  • Un intreg negativ – caz în care un mesaj cu tipul mai mare sau egal cu valoarea absolută a argumentului este returnat (în cazul în care flagul msgflg este setat corespunzător);

Argumentul msgflg specifică comportamentul funcţiei în condiţiile în care mesajul de tipul cerut nu există în coadă:

  • dacă IPC_NOWAIT este setat funcţia returnează eroare dacă nu există mesaj de tipul cerut în coadă. Dacă nu este setat funcţia blochează procesul apelant până când un mesaj de tipul cerut este adăugat în coadă sau până când coada este distrusă;
  • dacă MSG_EXCEPT este setat şi tipul mesajului cerut este un întreg pozitiv atunci returnează primul mesaj al cărui tip NU este egal cu tipul specificat;
  • dacă MSG_NOERROR este setat şi mesajul citit are conţinutul mai mare decât cel specificat prin msgsz atunci trunchează mesajul. Dacă falg-ul nu est especificat returnează mesaj de eroare.

Secvenţa de cod ce exemplifică citirea unui mesaj din coadă este dată în continuare:

    msgrcv(msgid,&mes,25,1,IPC_NOWAIT|MSG_ERROR);

Alte operatii cu cozi de mesaje

Funcţia de sistem msgctl are rolul de a efectua asupra structurii asociate cozii diverse operaţii: obţinerea de informaţii despre structură, modificarea informaţiilor structurii şi ştergerea structurii. Semnătura funcţiei semctl este:

     #include <sys/types.h>
     #include <sys/ipc.h>
     #include <sys/msg.h>
 
     int
     msgctl(int msqid, int cmd, struct msqid_ds *buf);

Pagina man asociată funcţiei msgctl este aceasta.

Un exemplu de folosire este pentru ştergerea structurii de mesaje:

      shmctl(shmid,IPC_RMID,0);