X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=56caf92637cb7f867130c134554b638387f9f3bf;hp=25274c996d97179f9ed1a53057c3c64bc8100b1f;hb=b99370b46df36884995d94ed00de41aa51b4e027;hpb=de83478a4dec2c8dd1b3721c4548b8d902555566 diff --git a/ipc.tex b/ipc.tex index 25274c9..56caf92 100644 --- a/ipc.tex +++ b/ipc.tex @@ -112,7 +112,7 @@ essere bloccante (qualora non siano presenti dati), inoltre se si legge da una pipe il cui capo in scrittura è stato chiuso, si avrà la ricezione di un EOF (vale a dire che la funzione \func{read} ritornerà restituendo 0). Se invece si esegue una scrittura su una pipe il cui capo in lettura non è aperto il -processo riceverà il segnale \errcode{EPIPE}, e la funzione di scrittura +processo riceverà il segnale \const{SIGPIPE}, e la funzione di scrittura restituirà un errore di \errcode{EPIPE} (al ritorno del gestore, o qualora il segnale sia ignorato o bloccato). @@ -190,55 +190,7 @@ nel file \file{BarCodePage.c} che si trova nella directory dei sorgenti. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -int main(int argc, char *argv[], char *envp[]) -{ - ... - /* create two pipes, pipein and pipeout, to handle communication */ - if ( (retval = pipe(pipein)) ) { - WriteMess("input pipe creation error"); - exit(0); - } - if ( (retval = pipe(pipeout)) ) { - WriteMess("output pipe creation error"); - exit(0); - } - /* First fork: use child to run barcode program */ - if ( (pid = fork()) == -1) { /* on error exit */ - WriteMess("child creation error"); - exit(0); - } - /* if child */ - if (pid == 0) { - close(pipein[1]); /* close pipe write end */ - dup2(pipein[0], STDIN_FILENO); /* remap stdin to pipe read end */ - close(pipeout[0]); - dup2(pipeout[1], STDOUT_FILENO); /* remap stdout in pipe output */ - execlp("barcode", "barcode", size, NULL); - } - close(pipein[0]); /* close input side of input pipe */ - write(pipein[1], argv[1], strlen(argv[1])); /* write parameter to pipe */ - close(pipein[1]); /* closing write end */ - waitpid(pid, NULL, 0); /* wait child completion */ - /* Second fork: use child to run ghostscript */ - if ( (pid = fork()) == -1) { - WriteMess("child creation error"); - exit(0); - } - /* second child, convert PS to JPEG */ - if (pid == 0) { - close(pipeout[1]); /* close write end */ - dup2(pipeout[0], STDIN_FILENO); /* remap read end to stdin */ - /* send mime type */ - write(STDOUT_FILENO, content, strlen(content)); - execlp("gs", "gs", "-q", "-sDEVICE=jpeg", "-sOutputFile=-", "-", NULL); - } - /* still parent */ - close(pipeout[1]); - waitpid(pid, NULL, 0); - exit(0); -} - \end{lstlisting} + \includecodesample{listati/BarCodePage.c} \end{minipage} \normalsize \caption{Sezione principale del codice del \textit{CGI} @@ -423,37 +375,7 @@ invocato dopo. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -int main(int argc, char *argv[], char *envp[]) -{ - FILE *pipe[4]; - FILE *pipein; - char *cmd_string[4]={ - "pnmtopng", - "pnmmargin -white 10", - "pnmcrop", - "gs -sDEVICE=ppmraw -sOutputFile=- -sNOPAUSE -q - -c showpage -c quit" - }; - char content[]="Content-type: image/png\n\n"; - int i; - /* write mime-type to stdout */ - write(STDOUT_FILENO, content, strlen(content)); - /* execute chain of command */ - for (i=0; i<4; i++) { - pipe[i] = popen(cmd_string[i], "w"); - dup2(fileno(pipe[i]), STDOUT_FILENO); - } - /* create barcode (in PS) */ - pipein = popen("barcode", "w"); - /* send barcode string to barcode program */ - write(fileno(pipein), argv[1], strlen(argv[1])); - /* close all pipes (in reverse order) */ - for (i=4; i==0; i--) { - pclose((pipe[i])); - } - exit(0); -} - \end{lstlisting} + \includecodesample{listati/BarCode.c} \end{minipage} \normalsize \caption{Codice completo del \textit{CGI} \file{BarCode.c}.} @@ -594,60 +516,7 @@ diverso da quelli preimpostati. Il codice completo \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -char *fifoname = "/tmp/fortune.fifo"; -int main(int argc, char *argv[]) -{ -/* Variables definition */ - int i, n = 0; - char *fortunefilename = "/usr/share/games/fortunes/linux"; - char **fortune; - char line[80]; - int fifo_server, fifo_client; - int nread; - ... - if (n==0) usage(); /* if no pool depth exit printing usage info */ - Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */ - Signal(SIGINT, HandSIGTERM); - Signal(SIGQUIT, HandSIGTERM); - i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */ - if (mkfifo(fifoname, 0622)) { /* create well known fifo if does't exist */ - if (errno!=EEXIST) { - perror("Cannot create well known fifo"); - exit(1); - } - } - daemon(0, 0); - /* open fifo two times to avoid EOF */ - fifo_server = open(fifoname, O_RDONLY); - if (fifo_server < 0) { - perror("Cannot open read only well known fifo"); - exit(1); - } - if (open(fifoname, O_WRONLY) < 0) { - perror("Cannot open write only well known fifo"); - exit(1); - } - /* Main body: loop over requests */ - while (1) { - nread = read(fifo_server, line, 79); /* read request */ - if (nread < 0) { - perror("Read Error"); - exit(1); - } - line[nread] = 0; /* terminate fifo name string */ - n = random() % i; /* select random value */ - fifo_client = open(line, O_WRONLY); /* open client fifo */ - if (fifo_client < 0) { - perror("Cannot open"); - exit(1); - } - nread = write(fifo_client, /* write phrase */ - fortune[n], strlen(fortune[n])+1); - close(fifo_client); /* close client fifo */ - } -} - \end{lstlisting} + \includecodesample{listati/FortuneServer.c} \end{minipage} \normalsize \caption{Sezione principale del codice del server di \textit{fortunes} @@ -737,44 +606,7 @@ principale del programma e le definizioni delle variabili. Il codice completo \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -int main(int argc, char *argv[]) -{ -/* Variables definition */ - int n = 0; - char *fortunefilename = "/tmp/fortune.fifo"; - char line[80]; - int fifo_server, fifo_client; - char fifoname[80]; - int nread; - char buffer[PIPE_BUF]; - ... - snprintf(fifoname, 80, "/tmp/fortune.%d", getpid()); /* compose name */ - if (mkfifo(fifoname, 0622)) { /* open client fifo */ - if (errno!=EEXIST) { - perror("Cannot create well known fifo"); - exit(-1); - } - } - fifo_server = open(fortunefilename, O_WRONLY); /* open server fifo */ - if (fifo_server < 0) { - perror("Cannot open well known fifo"); - exit(-1); - } - nread = write(fifo_server, fifoname, strlen(fifoname)+1); /* write name */ - close(fifo_server); /* close server fifo */ - fifo_client = open(fifoname, O_RDONLY); /* open client fifo */ - if (fifo_client < 0) { - perror("Cannot open well known fifo"); - exit(-1); - } - nread = read(fifo_client, buffer, sizeof(buffer)); /* read answer */ - printf("%s", buffer); /* print fortune */ - close(fifo_client); /* close client */ - close(fifo_server); /* close server */ - unlink(fifoname); /* remove client fifo */ -} - \end{lstlisting} + \includecodesample{listati/FortuneClient.c} \end{minipage} \normalsize \caption{Sezione principale del codice del client di \textit{fortunes} @@ -1002,18 +834,7 @@ mantiene varie propriet \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm ]{} -struct ipc_perm -{ - key_t key; /* Key. */ - uid_t uid; /* Owner's user ID. */ - gid_t gid; /* Owner's group ID. */ - uid_t cuid; /* Creator's user ID. */ - gid_t cgid; /* Creator's group ID. */ - unsigned short int mode; /* Read/write permission. */ - unsigned short int seq; /* Sequence number. */ -}; - \end{lstlisting} + \includestruct{listati/ipc_perm.h} \end{minipage} \normalsize \caption{La struttura \structd{ipc\_perm}, come definita in @@ -1210,41 +1031,7 @@ s \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -int main(int argc, char *argv[]) -{ - ... - switch (type) { - case 'q': /* Message Queue */ - debug("Message Queue Try\n"); - for (i=0; i 0 */ - char mtext[LENGTH]; /* message data */ - }; - \end{lstlisting} + \includestruct{listati/msgbuf.h} \end{minipage} \normalsize \caption{Schema della struttura \structd{msgbuf}, da utilizzare come @@ -1755,57 +1523,8 @@ in maniera indipendente con client diversi. \begin{figure}[!bht] \footnotesize \centering - \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -int msgid; /* Message queue identifier */ -int main(int argc, char *argv[]) -{ -/* Variables definition */ - int i, n = 0; - char **fortune; /* array of fortune message string */ - char *fortunefilename = "/usr/share/games/fortunes/linux"; /* file name */ - struct msgbuf_read { /* message struct to read request from clients */ - long mtype; /* message type, must be 1 */ - long pid; /* message data, must be the pid of the client */ - } msg_read; - struct msgbuf_write { /* message struct to write result to clients */ - long mtype; /* message type, will be the pid of the client*/ - char mtext[MSGMAX]; /* message data, will be the fortune */ - } msg_write; - key_t key; /* Message queue key */ - int size; /* message size */ - ... - Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */ - Signal(SIGINT, HandSIGTERM); - Signal(SIGQUIT, HandSIGTERM); - if (n==0) usage(); /* if no pool depth exit printing usage info */ - i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */ - /* Create the queue */ - key = ftok("./MQFortuneServer.c", 1); - msgid = msgget(key, IPC_CREAT|0666); - if (msgid < 0) { - perror("Cannot create message queue"); - exit(1); - } - /* Main body: loop over requests */ - daemon(0, 0); - while (1) { - msgrcv(msgid, &msg_read, sizeof(int), 1, MSG_NOERROR); - n = random() % i; /* select random value */ - strncpy(msg_write.mtext, fortune[n], MSGMAX); - size = min(strlen(fortune[n])+1, MSGMAX); - msg_write.mtype=msg_read.pid; /* use request pid as type */ - msgsnd(msgid, &msg_write, size, 0); - } -} -/* - * Signal Handler to manage termination - */ -void HandSIGTERM(int signo) { - msgctl(msgid, IPC_RMID, NULL); /* remove message queue */ - exit(0); -} - \end{lstlisting} + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/MQFortuneServer.c} \end{minipage} \normalsize \caption{Sezione principale del codice del server di \textit{fortunes} @@ -1878,26 +1597,8 @@ gestore \code{HandSIGTERM}, che semplicemente si limita a cancellare la coda \begin{figure}[!bht] \footnotesize \centering - \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -int main(int argc, char *argv[]) -{ - ... - key = ftok("./MQFortuneServer.c", 1); - msgid = msgget(key, 0); - if (msgid < 0) { - perror("Cannot find message queue"); - exit(1); - } - /* Main body: do request and write result */ - msg_read.mtype = 1; /* type for request is always 1 */ - msg_read.pid = getpid(); /* use pid for communications */ - size = sizeof(msg_read.pid); - msgsnd(msgid, &msg_read, size, 0); /* send request message */ - msgrcv(msgid, &msg_write, MSGMAX, msg_read.pid, MSG_NOERROR); - printf("%s", msg_write.mtext); -} - \end{lstlisting} + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/MQFortuneClient.c} \end{minipage} \normalsize \caption{Sezione principale del codice del client di \textit{fortunes} @@ -2087,15 +1788,7 @@ semaforo all'uscita del processo. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{} -struct semid_ds -{ - struct ipc_perm sem_perm; /* operation permission struct */ - time_t sem_otime; /* last semop() time */ - time_t sem_ctime; /* last time changed by semctl() */ - unsigned long int sem_nsems; /* number of semaphores in set */ -}; - \end{lstlisting} + \includestruct{listati/semid_ds.h} \end{minipage} \normalsize \caption{La struttura \structd{semid\_ds}, associata a ciascun insieme di @@ -2137,14 +1830,7 @@ controllo. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{} -struct sem { - short sempid; /* pid of last operation */ - ushort semval; /* current value */ - ushort semncnt; /* num procs awaiting increase in semval */ - ushort semzcnt; /* num procs awaiting semval = 0 */ -}; - \end{lstlisting} + \includestruct{listati/sem.h} \end{minipage} \normalsize \caption{La struttura \structd{sem}, che contiene i dati di un singolo @@ -2234,15 +1920,7 @@ specificata con \param{cmd}, ed opera o sull'intero insieme specificato da \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{} -union semun { - int val; /* value for SETVAL */ - struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ - unsigned short *array; /* array for GETALL, SETALL */ - /* Linux specific part: */ - struct seminfo *__buf; /* buffer for IPC_INFO */ -}; - \end{lstlisting} + \includestruct{listati/semun.h} \end{minipage} \normalsize \caption{La definizione dei possibili valori di una \direct{union} @@ -2388,14 +2066,7 @@ effettivamente eseguite se e soltanto se \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{} -struct sembuf -{ - unsigned short int sem_num; /* semaphore number */ - short int sem_op; /* semaphore operation */ - short int sem_flg; /* operation flag */ -}; - \end{lstlisting} + \includestruct{listati/sembuf.h} \end{minipage} \normalsize \caption{La struttura \structd{sembuf}, usata per le operazioni sui @@ -2571,57 +2242,7 @@ nullo per segnalarne l'indisponibilit \begin{figure}[!bht] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -/* Function MutexCreate: create a mutex/semaphore */ -int MutexCreate(key_t ipc_key) -{ - const union semun semunion={1}; /* semaphore union structure */ - int sem_id, ret; - sem_id = semget(ipc_key, 1, IPC_CREAT|0666); /* get semaphore ID */ - if (sem_id == -1) { /* if error return code */ - return sem_id; - } - ret = semctl(sem_id, 0, SETVAL, semunion); /* init semaphore */ - if (ret == -1) { - return ret; - } - return sem_id; -} -/* Function MutexFind: get the semaphore/mutex Id given the IPC key value */ -int MutexFind(key_t ipc_key) -{ - return semget(ipc_key,1,0); -} -/* Function MutexRead: read the current value of the mutex/semaphore */ -int MutexRead(int sem_id) -{ - return semctl(sem_id, 0, GETVAL); -} -/* Define sembuf structures to lock and unlock the semaphore */ -struct sembuf sem_lock={ /* to lock semaphore */ - 0, /* semaphore number (only one so 0) */ - -1, /* operation (-1 to use resource) */ - SEM_UNDO}; /* flag (set for undo at exit) */ -struct sembuf sem_ulock={ /* to unlock semaphore */ - 0, /* semaphore number (only one so 0) */ - 1, /* operation (1 to release resource) */ - SEM_UNDO}; /* flag (in this case 0) */ -/* Function MutexLock: to lock a mutex/semaphore */ -int MutexLock(int sem_id) -{ - return semop(sem_id, &sem_lock, 1); -} -/* Function MutexUnlock: to unlock a mutex/semaphore */ -int MutexUnlock(int sem_id) -{ - return semop(sem_id, &sem_ulock, 1); -} -/* Function MutexRemove: remove a mutex/semaphore */ -int MutexRemove(int sem_id) -{ - return semctl(sem_id, 0, IPC_RMID); -} - \end{lstlisting} + \includecodesample{listati/Mutex.c} \end{minipage} \normalsize \caption{Il codice delle funzioni che permettono di creare o recuperare @@ -2749,18 +2370,7 @@ norma, significa insieme a dei semafori. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{} -struct shmid_ds { - struct ipc_perm shm_perm; /* operation perms */ - int shm_segsz; /* size of segment (bytes) */ - time_t shm_atime; /* last attach time */ - time_t shm_dtime; /* last detach time */ - time_t shm_ctime; /* last change time */ - unsigned short shm_cpid; /* pid of creator */ - unsigned short shm_lpid; /* pid of last operator */ - short shm_nattch; /* no. of current attaches */ -}; - \end{lstlisting} + \includestruct{listati/shmid_ds.h} \end{minipage} \normalsize \caption{La struttura \structd{shmid\_ds}, associata a ciascun segmento di @@ -2776,7 +2386,7 @@ campo \var{shm\_perm} viene inizializzato come illustrato in \secref{sec:ipc_sysv_access_control}, e valgono le considerazioni ivi fatte relativamente ai permessi di accesso; per quanto riguarda gli altri campi invece: -\begin{itemize*} +\begin{itemize} \item il campo \var{shm\_segsz}, che esprime la dimensione del segmento, viene inizializzato al valore di \param{size}. \item il campo \var{shm\_ctime}, che esprime il tempo di creazione del @@ -2790,7 +2400,7 @@ invece: creato il segmento, viene inizializzato al \acr{pid} del processo chiamante. \item il campo \var{shm\_nattac}, che esprime il numero di processi agganciati al segmento viene inizializzato a zero. -\end{itemize*} +\end{itemize} Come per le code di messaggi e gli insiemi di semafori, anche per i segmenti di memoria condivisa esistono una serie di limiti imposti dal sistema. Alcuni @@ -3044,67 +2654,10 @@ In caso di successo la funzione aggiorna anche i seguenti campi di inoltre la regione di indirizzi usata per il segmento di memoria condivisa viene tolta dallo spazio di indirizzi del processo. -Come esempio di uso di queste funzioni vediamo come implementare una serie di -funzioni di libreria che ne semplifichino l'uso, automatizzando le operazioni -più comuni; il codice, contenuto nel file \file{SharedMem.c}, è riportato in -\figref{fig:ipc_sysv_shm_func}. - \begin{figure}[!bht] \footnotesize \centering - \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -/* Function ShmCreate Create a SysV shared memory segment */ -void * ShmCreate(key_t ipc_key, int shm_size, int perm, int fill) -{ - void * shm_ptr; - int shm_id; /* ID of the IPC shared memory segment */ - shm_id = shmget(ipc_key, shm_size, IPC_CREAT|perm); /* get shm ID */ - if (shm_id < 0) { - return NULL; - } - shm_ptr = shmat(shm_id, NULL, 0); /* map it into memory */ - if (shm_ptr < 0) { - return NULL; - } - memset((void *)shm_ptr, fill, shm_size); /* fill segment */ - return shm_ptr; -} -/* Function ShmFind: Find a SysV shared memory segment */ -void * ShmFind(key_t ipc_key, int shm_size) -{ - void * shm_ptr; - int shm_id; /* ID of the SysV shared memory segment */ - shm_id = shmget(ipc_key, shm_size, 0); /* find shared memory ID */ - if (shm_id < 0) { - return NULL; - } - shm_ptr = shmat(shm_id, NULL, 0); /* map it into memory */ - if (shm_ptr < 0) { - return NULL; - } - return shm_ptr; -} -/* Function ShmRemove: Schedule removal for a SysV shared memory segment */ -int ShmRemove(key_t ipc_key, void * shm_ptr) -{ - int shm_id; /* ID of the SysV shared memory segment */ - /* first detach segment */ - if (shmdt(shm_ptr) < 0) { - return -1; - } - /* schedule segment removal */ - shm_id = shmget(ipc_key, 0, 0); /* find shared memory ID */ - if (shm_id < 0) { - if (errno == EIDRM) return 0; - return -1; - } - if (shmctl(shm_id, IPC_RMID, NULL) < 0) { /* ask for removal */ - if (errno == EIDRM) return 0; - return -1; - } - return 0; -} - \end{lstlisting} + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/SharedMem.c} \end{minipage} \normalsize \caption{Il codice delle funzioni che permettono di creare, trovare e @@ -3112,6 +2665,11 @@ int ShmRemove(key_t ipc_key, void * shm_ptr) \label{fig:ipc_sysv_shm_func} \end{figure} +Come esempio di uso di queste funzioni vediamo come implementare una serie di +funzioni di libreria che ne semplifichino l'uso, automatizzando le operazioni +più comuni; il codice, contenuto nel file \file{SharedMem.c}, è riportato in +\figref{fig:ipc_sysv_shm_func}. + La prima funzione (\texttt{\small 3--16}) è \func{ShmCreate} che, data una chiave, crea il segmento di memoria condivisa restituendo il puntatore allo stesso. La funzione comincia (\texttt{\small 6}) con il chiamare @@ -3185,58 +2743,8 @@ video; al solito il codice completo si trova con i sorgenti allegati nel file \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -/* global variables for shared memory segment */ -struct DirProp { - int tot_size; - int tot_files; - int tot_regular; - int tot_fifo; - int tot_link; - int tot_dir; - int tot_block; - int tot_char; - int tot_sock; -} *shmptr; -key_t key; -int mutex; -/* main body */ -int main(int argc, char *argv[]) -{ - int i, pause = 10; - ... - if ((argc - optind) != 1) { /* There must be remaing parameters */ - printf("Wrong number of arguments %d\n", argc - optind); - usage(); - } - if (chdir(argv[1])) { /* chdir to be sure dir exist */ - perror("Cannot find directory to monitor"); - } - Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */ - Signal(SIGINT, HandSIGTERM); - Signal(SIGQUIT, HandSIGTERM); - key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */ - shmptr = ShmCreate(key, 4096, 0666, 0); /* get a shared memory segment */ - if (!shmptr) { - perror("Cannot create shared memory"); - exit(1); - } - if ((mutex = MutexCreate(key)) == -1) { /* get a Mutex */ - perror("Cannot create mutex"); - exit(1); - } - /* main loop, monitor directory properties each 10 sec */ - daemon(1, 0); /* demonize process, staying in monitored dir */ - while (1) { - MutexLock(mutex); /* lock shared memory */ - memset(shmptr, 0, sizeof(struct DirProp)); /* erase previous data */ - DirScan(argv[1], ComputeValues); /* execute scan */ - MutexUnlock(mutex); /* unlock shared memory */ - sleep(pause); /* sleep until next watch */ - } -} - \end{lstlisting} + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/DirMonitor.c} \end{minipage} \normalsize \caption{Codice della funzione principale del programma \file{DirMonitor.c}.} @@ -3287,6 +2795,16 @@ sar di interfaccia già descritte in \secref{sec:ipc_sysv_sem}, anche un mutex, che utilizzeremo per regolare l'accesso alla memoria condivisa. +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/ComputeValues.c} + \end{minipage} + \normalsize + \caption{Codice delle funzioni ausiliarie usate da \file{DirMonitor.c}.} + \label{fig:ipc_dirmonitor_sub} +\end{figure} + Completata l'inizializzazione e la creazione degli oggetti di intercomunicazione il programma entra nel ciclo principale (\texttt{\small 40--49}) dove vengono eseguite indefinitamente le attività di monitoraggio. @@ -3305,41 +2823,6 @@ degli stessi utilizzando la funzione \func{DirScan}; infine (\texttt{\small (\texttt{\small 47}) per il periodo di tempo specificato a riga di comando con l'opzione \code{-p} con una \func{sleep}. - -\begin{figure}[!htb] - \footnotesize \centering - \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -/* Routine to compute directory properties inside DirScan */ -int ComputeValues(struct dirent * direntry) -{ - struct stat data; - stat(direntry->d_name, &data); /* get stat data */ - shmptr->tot_size += data.st_size; - shmptr->tot_files++; - if (S_ISREG(data.st_mode)) shmptr->tot_regular++; - if (S_ISFIFO(data.st_mode)) shmptr->tot_fifo++; - if (S_ISLNK(data.st_mode)) shmptr->tot_link++; - if (S_ISDIR(data.st_mode)) shmptr->tot_dir++; - if (S_ISBLK(data.st_mode)) shmptr->tot_block++; - if (S_ISCHR(data.st_mode)) shmptr->tot_char++; - if (S_ISSOCK(data.st_mode)) shmptr->tot_sock++; - return 0; -} -/* Signal Handler to manage termination */ -void HandSIGTERM(int signo) { - MutexLock(mutex); - ShmRemove(key, shmptr); - MutexRemove(mutex); - exit(0); -} - \end{lstlisting} - \end{minipage} - \normalsize - \caption{Codice delle funzione ausiliarie usate da \file{DirMonitor.c}.} - \label{fig:ipc_dirmonitor_sub} -\end{figure} - Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si sia usata ancora una volta la funzione \func{DirScan}, già utilizzata (e descritta in dettaglio) in \secref{sec:file_dir_read}, che ci permette di @@ -3374,36 +2857,8 @@ rimuove il mutex con \func{MutexRemove} ed esce (\texttt{\small 22}). \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -int main(int argc, char *argv[]) -{ - key_t key; - ... - /* create needed IPC objects */ - key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */ - if (!(shmptr = ShmFind(key, 4096))) { /* get a shared memory segment */ - perror("Cannot find shared memory"); - exit(1); - } - if ((mutex = MutexFind(key)) == -1) { /* get the Mutex */ - perror("Cannot find mutex"); - exit(1); - } - /* main loop */ - MutexLock(mutex); /* lock shared memory */ - printf("Ci sono %d file dati\n", shmptr->tot_regular); - printf("Ci sono %d directory\n", shmptr->tot_dir); - printf("Ci sono %d link\n", shmptr->tot_link); - printf("Ci sono %d fifo\n", shmptr->tot_fifo); - printf("Ci sono %d socket\n", shmptr->tot_sock); - printf("Ci sono %d device a caratteri\n", shmptr->tot_char); - printf("Ci sono %d device a blocchi\n", shmptr->tot_block); - printf("Totale %d file, per %d byte\n", - shmptr->tot_files, shmptr->tot_size); - MutexUnlock(mutex); /* unlock shared memory */ -} - \end{lstlisting} + \begin{minipage}[c]{15.6 cm} + \includecodesample{listati/ReadMonitor.c} \end{minipage} \normalsize \caption{Codice del programma client del monitor delle proprietà di una @@ -3592,26 +3047,8 @@ cancella con \func{unlink}. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -#include -#include -#include /* unix standard functions */ -/* - * Function LockFile: - */ -int LockFile(const char* path_name) -{ - return open(path_name, O_EXCL|O_CREAT); -} -/* - * Function UnlockFile: - */ -int UnlockFile(const char* path_name) -{ - return unlink(path_name); -} - \end{lstlisting} + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/LockFile.c} \end{minipage} \normalsize \caption{Il codice delle funzioni \func{LockFile} e \func{UnlockFile} che @@ -3672,64 +3109,8 @@ leggermente pi \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -/* Function CreateMutex: Create a mutex using file locking. */ -int CreateMutex(const char *path_name) -{ - return open(path_name, O_EXCL|O_CREAT); -} -/* Function UnlockMutex: unlock a file. */ -int FindMutex(const char *path_name) -{ - return open(path_name, O_RDWR); -} -/* Function LockMutex: lock mutex using file locking. */ -int LockMutex(int fd) -{ - struct flock lock; /* file lock structure */ - /* set flock structure */ - lock.l_type = F_WRLCK; /* set type: read or write */ - lock.l_whence = SEEK_SET; /* start from the beginning of the file */ - lock.l_start = 0; /* set the start of the locked region */ - lock.l_len = 0; /* set the length of the locked region */ - /* do locking */ - return fcntl(fd, F_SETLKW, &lock); -} -/* Function UnlockMutex: unlock a file. */ -int UnlockMutex(int fd) -{ - struct flock lock; /* file lock structure */ - /* set flock structure */ - lock.l_type = F_UNLCK; /* set type: unlock */ - lock.l_whence = SEEK_SET; /* start from the beginning of the file */ - lock.l_start = 0; /* set the start of the locked region */ - lock.l_len = 0; /* set the length of the locked region */ - /* do locking */ - return fcntl(fd, F_SETLK, &lock); -} -/* Function RemoveMutex: remove a mutex (unlinking the lock file). */ -int RemoveMutex(const char *path_name) -{ - return unlink(path_name); -} -/* Function ReadMutex: read a mutex status. */ -int ReadMutex(int fd) -{ - int res; - struct flock lock; /* file lock structure */ - /* set flock structure */ - lock.l_type = F_WRLCK; /* set type: unlock */ - lock.l_whence = SEEK_SET; /* start from the beginning of the file */ - lock.l_start = 0; /* set the start of the locked region */ - lock.l_len = 0; /* set the length of the locked region */ - /* do locking */ - if ( (res = fcntl(fd, F_GETLK, &lock)) ) { - return res; - } - return lock.l_type; -} - \end{lstlisting} + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/MutexLocking.c} \end{minipage} \normalsize \caption{Il codice delle funzioni che permettono per la gestione dei @@ -3924,7 +3305,7 @@ per Benedyczak,\footnote{i patch al kernel e la relativa libreria possono essere trovati su \href{http://www.mat.uni.torun.pl/~wrona/posix_ipc} -{http://www.mat.uni.torun.pl/\~{}wrona/posix\_ipc}.}. +{http://www.mat.uni.torun.pl/\tild{}wrona/posix\_ipc}.}. In generale, come le corrispettive del SysV IPC, le code di messaggi sono poco usate, dato che i socket\index{socket}, nei casi in cui sono sufficienti, sono più comodi, e che in casi più complessi la comunicazione può essere gestita @@ -4037,14 +3418,7 @@ struttura \struct{mq\_attr}, la cui definizione \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{} -struct mq_attr { - long mq_flags; /* message queue flags */ - long mq_maxmsg; /* maximum number of messages */ - long mq_msgsize; /* maximum message size */ - long mq_curmsgs; /* number of messages currently queued */ -}; - \end{lstlisting} + \includestruct{listati/mq_attr.h} \end{minipage} \normalsize \caption{La struttura \structd{mq\_attr}, contenente gli attributi di una @@ -4509,60 +3883,13 @@ mappati in memoria; questi verranno cancellati automaticamente dal sistema solo con le rispettive chiamate a \func{close} e \func{munmap}. Una volta eseguita questa funzione però, qualora si richieda l'apertura di un segmento con lo stesso nome, la chiamata a \func{shm\_open} fallirà, a meno di non aver -usato \const{O\_CREAT}, nel qual caso comunque si otterrà il riferimento ad un -segmento distinto dal precedente. +usato \const{O\_CREAT}, in quest'ultimo caso comunque si otterrà un file +descriptor che fa riferimento ad un segmento distinto da eventuali precedenti. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -/* Function CreateShm: Create a shared memory segment mapping it */ -void * CreateShm(char * shm_name, off_t shm_size, mode_t perm, int fill) -{ - void * shm_ptr; - int fd; - int flag; - /* first open the object, creating it if not existent */ - flag = O_CREAT|O_EXCL|O_RDWR; - fd = shm_open(shm_name, flag, perm); /* get object file descriptor */ - if (fd < 0) { - return NULL; - } - /* set the object size */ - if (ftruncate(fd, shm_size)) { - return NULL; - } - /* map it in the process address space */ - shm_ptr = mmap(NULL, shm_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0); - if (shm_ptr == MAP_FAILED) { - return NULL; - } - memset((void *) shm_ptr, fill, shm_size); /* fill segment */ - return shm_ptr; -} -/* Function FindShm: Find a POSIX shared memory segment */ -void * FindShm(char * shm_name, off_t shm_size) -{ - void * shm_ptr; - int fd; /* ID of the IPC shared memory segment */ - /* find shared memory ID */ - if ((fd = shm_open(shm_name, O_RDWR|O_EXCL, 0)) < 0) { - return NULL; - } - /* take the pointer to it */ - shm_ptr = mmap(NULL, shm_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0); - if (shm_ptr == MAP_FAILED) { - return NULL; - } - return shm_ptr; -} -/* Function RemoveShm: Remove a POSIX shared memory segment */ -int RemoveShm(char * shm_name) -{ - shm_unlink(shm_name); - return 0; -} - \end{lstlisting} + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/MemShared.c} \end{minipage} \normalsize \caption{Il codice delle funzioni di gestione dei segmenti di memoria @@ -4570,16 +3897,17 @@ int RemoveShm(char * shm_name) \label{fig:ipc_posix_shmmem} \end{figure} -Come esempio di queste funzioni vediamo come è possibile riscrivere con esse -funzioni analoghe a quelle viste in \secref{fig:ipc_sysv_shm_func}; il codice, -riportato in \figref{fig:ipc_posix_shmmem}, è sempre contenuto nel file -\file{SharedMem.c} dei sorgenti allegati. +Come esempio per l'uso di queste funzioni vediamo come è possibile riscrivere +una interfaccia semplificata analoga a quella vista in +\secref{fig:ipc_sysv_shm_func} per la memoria condivisa in stile SysV. Il +codice, riportato in \figref{fig:ipc_posix_shmmem}, è sempre contenuto nel +file \file{SharedMem.c} dei sorgenti allegati. La prima funzione (\texttt{\small 1--24}) è \func{CreateShm} che, dato un nome nell'argomento \var{name} crea un nuovo segmento di memoria condivisa, accessibile in lettura e scrittura, e ne restituisce l'indirizzo. Anzitutto si definiscono (\texttt{\small 8}) i flag per la successiva (\texttt{\small 9}) -chiamata a \func{shm\_open} che apre il segmento in lettura e scrittura +chiamata a \func{shm\_open}, che apre il segmento in lettura e scrittura (creandolo se non esiste, ed uscendo in caso contrario) assegnandogli sul filesystem i permessi specificati dall'argomento \var{perm}. In caso di errore (\texttt{\small 10--12}) si restituisce un puntatore nullo, altrimenti si @@ -4603,11 +3931,12 @@ memoria con \func{mmap}, restituendo (\texttt{\small 36--38}) un puntatore nullo in caso di errore, o l'indirizzo (\texttt{\small 39}) dello stesso in caso di successo. -La terza funzione (\texttt{\small 40--46}) è \func{FindShm}, e serve a +La terza funzione (\texttt{\small 40--45}) è \func{RemoveShm}, e serve a cancellare un segmento di memoria condivisa. Dato che al contrario di quanto avveniva con i segmenti del SysV IPC gli oggetti allocati nel kernel vengono rilasciati automaticamente quando nessuna li usa più, tutto quello che c'è da -fare (\texttt{\small 45}) in questo caso è chiamare \func{shm\_unlink}. +fare (\texttt{\small 44}) in questo caso è chiamare \func{shm\_unlink}, +retituendo al chiamante il valore di ritorno.