• Non ci sono risultati.

Chiamate di sitema

N/A
N/A
Protected

Academic year: 2021

Condividi "Chiamate di sitema"

Copied!
30
0
0

Testo completo

(1)

Chiamate di sistema

Pipe

(2)

Esempio di chiamata di sistema

#include <stdio.h>

int main(int argc, char ** argv)

{

FILE * f;

f = fopen("nuovo-file", "w");

fprintf(f, "Hello World!\n");

fclose(f);

(3)

Esempio chiamata di sistema

#include <stdio.h>

#include <sys/fcntl.h>

int main(int argc, char ** argv)

{

int fd; // file descriptor

fd = open("nuovo-file", O_WRONLY |

O_CREAT, 0666);

write(fd, "Hello World\n", 12);

close(fd);

}

0 1 2 ... stdin stdout stderr ... File

(4)

Pipe

• Questa comunicazione tra processi appare al

programmatore simile alla scrittura-lettura dei file

• Una pipe è un file di dimensione limitata gestito come una

coda FIFO:

– un processo produttore deposita dati (e resta in attesa se la

pipe è piena)

– un processo consumatore legge dati (e resta in attesa se la

coda è vuota)

(5)

POSIX: creazione di pipe

• pipe senza nome, create e aperte da

pipe

int

pipe

(int

fd

[2]);

• crea una pipe, la apre in lettura e scrittura

• restituisce l'esito dell'operazione (0 o -1)

• assegna a

fd

[0] il file descriptor del lato aperto in lettura, e

a

fd

[1] quello del lato aperto in scrittura

• Si possono creare pipe con nome, devono essere create da

(6)

POSIX: creazione di pipe

$ mknod fifo1 p $ ls -l fifo*

prw-rw-rw- 1 lucal lucal 0 Apr 19 09:11 fifo1 (si noti la p nei permessi) $ mkfifo fifo2

$ ls -l fifo*

prw-rw-rw- 1 lucal lucal 0 Apr 19 09:11 fifo1 prw-rw-rw- 1 lucal lucal 0 Apr 19 09:11 fifo2 $ cat fifo1 & echo ciao > fifo1

[1] 8088 ciao

$ cat fifo2 ; echo ciao > fifo2

(cursore lampeggiante: il programma è bloccato)

Ovviamente fifo1 e fifo2 sono equivalenti (ma diversi) osboxes@osboxes: ~

(7)

File e pipe ordinari

• Creazione e uso di un file ordinario:

int fd;

...

if ((fd=open(filename,...)<0) err();

...

write(fd, …); …;

• Creazione e uso di una pipe (senza nome):

int fd[2];

...

if (pipe(fd) < 0) err();

...

write(fd[1], …); …; read(fd[0], …);

Note:

– la pipe è analoga a open, ma non specifica il nome

e produce

due

file descriptor

(8)

Pipe: uso tipico

• Generalmente una pipe viene usata per far comunicare un

processo padre con un suo figlio

• Il processo figlio eredita i file aperti, quindi anche le pipe

– La comunicazione è unidirezionale

pipe

write(fd[1]);

read(fd[0]);

write(fd[1]);

read(fd[0]);

pipe

oppure

pipe(fd);

fork();

Processo figlio

Processo padre

(9)

Pipe: uso tipico

#include <stdio.h>;

int main(int argc, char ** argv) {

int fd[2], pid, status; char i, j, i1, j1;

pipe(fd);

pid = fork();

if(pid!=0) { // padre

for(i=0; i<10; i++) write(fd[1], &i, 1); printf("scritto!\n");

waitpid(-1, &status, 0);

printf("pid=%d i1=%d j=%d\n", pid, i1, j); } else { // figlio

for(j=0; j<10; j++) {

read(fd[0], &j1, 1); printf("j1=%d\n",j1); }

printf("pid=%d i=%d\n", pid, i); }

(10)

Pipe: comunicazione bidirezionale

int main(int argc, char ** argv) { int fd[2], fd2[2], pid; char i, j; pipe(fd); pipe(fd2); pid = fork(); if(pid!=0) {

for(i=0; i<10; i++) write(fd[1], &i, 1); read(fd2[0], &j, 1);

printf("pid=%d i=%d j=%d\n", pid, i, j); } else {

for(j=0; j<10; j++) {

read(fd[0], &i, 1); printf("i=%d\n", i); }

write(fd2[1], &j, 1);

printf("pid=%d i=%d j=%d\n", pid, i, j); }

(11)

Pipe: uso tipico

% cat documento.txt | sort

fork();

fork();

exec(“cat”, …);

exec(“cat”, …);

close(1);

dup(fd[1]);

close(fd[0]);

close(fd[1]);

close(1);

dup(fd[1]);

close(fd[0]);

close(fd[1]);

pipe(fd);

fork();

pipe(fd);

fork();

exec(“sort”, …);

exec(“sort”, …);

close(0);

dup(fd[0]);

close(fd[0]);

close(fd[1]);

close(0);

dup(fd[0]);

close(fd[0]);

close(fd[1]);

shell

processo figlio

Produttore

Consumatore

(12)

Realizzazione

0 1 2 ... ... stdin stdout stderr ... ... File

descriptor File table

pipe(fd); 0 1 2 3 4 stdin stdout stderr pipe-in pipe-out close(1); 0 1 2 3 4 stdin ... stderr pipe-in pipe-out dup(fd[1]); close(fd[0]); close(fd[1]); 0 1 2 3 stdin ... stderr ... 1) 2a) 3a) 4a) 0 1 2 3 4 stdin ... stderr pipe-in pipe-out close(0); 0 1 2 3 4 ... stdout stderr pipe-in pipe-out dup(fd[0]); close(fd[0]); close(fd[1]); 0 1 2 3 ... stdout stderr pipe-in 2b) 3b) 4b) 0 1 2 3 4 ... stdout stderr pipe-in pipe-out

(13)

Pipe: realizzazione

#include <stdio.h>

int main(int argc, char ** argv) { int fd[2], pid; char j, j1; pipe(fd); 1) pid = fork(); if(!pid) {

close(1); dup(fd[1]); 2a)-3a)

close(fd[0]); close(fd[1]); 4a)

execlp("cat", "cat", __FILE__, NULL); } else {

close(0); dup(fd[0]); 2b)-3b)

close(fd[0]); close(fd[1]); 4b)

for(j=0; j<10; j++) {

read(0, &j1, 1); printf("j1=%3d %c\n", j1,j1); }

}

fprintf(stderr, "pid=%d j1=%d j=%d\n", pid, j1, j); }

(14)

Risultato

j1= 35 #

j1=105 i

j1=110 n

j1= 99 c

j1=108 l

j1=117 u

j1=100 d

j1=101 e

j1= 32

j1= 60 <;

pid=1070 j1=60 j=10

(15)

Ridirezioni

% ls -l . pippo > ris 2>log

fork();

fork();

exec(“ls”, …);

exec(“ls”, …);

close(1);

open(“ris”, …);

close(2);

open(“log”, …);

close(1);

open(“ris”, …);

close(2);

open(“log”, …);

shell

processo figlio

(16)

Ridirezioni: realizzazione

#include <stdio.h> #include <unistd.h> #include <sys/fcntl.h>

int main(int argc, char ** argv) {

close(1);

open("ris", O_WRONLY | O_CREAT | O_TRUNC, 0666); close(2);

open("log", O_WRONLY | O_CREAT | O_TRUNC, 0666); execlp("ls", "LS", "-l", ".", "pippo", NULL); /* non dovrebbe mai essere eseguito */

fprintf(stderr, "Error: execlp\n"); return 1;

}

File “log”:

(17)

Semaforo tramite pipe

int up(int *pipe) {

char tmp = 0;

return write(pipe[1],&tmp,1)==1? 0 : -1; }

int down(int *pipe) { char tmp = 0; return read(pipe[0],&tmp,1)==1 ? 0 : -1; } int mk_mutex(int *p) {

if( pipe(p) < 0) return -1;

return write(p[1], p, 1) == 1 ? 0 : -1; }

Nota 1:

Il valore effettivamente letto o o scritto non ha importanza, conta solo il numero di byte letti o scritti

Nota 2:

Anche l’operazione di up può diventare bloccante (quando si riempie il buffer)

(18)

Semaforo tramite pipe

import java.io.*;

public class Semaforo { private PipedReader in; private PipedWriter out; public void down() { try {

in.read();

} catch(IOException e) { } }

public void up() { try { out.write(0); } catch(IOException e) { } } public Semaforo() { this(0); } public Semaforo(int v) { try { in = new PipedReader(); out = new PipedWriter(in); while(v-- > 0) up();

(19)

popen

#include <stdio.h> #include <stdlib.h>

int main(int argc, char **argv) {

FILE *pin; char line[10];

pin = popen("cat " __FILE__, "r"); fread(line, 1, 10, pin);

fwrite(line, 1, 10, stdout); pclose(pin);

return 0; }

(20)

popen

/* equivale a ls –l | sort */ #include <stdio.h>

#include <stdlib.h>

int main(int argc, char ** argv) {

FILE * pp, * pout; char line[100];

pp = popen("ls -l", "r"); pout = popen("sort", "w"); if(!pp || !pout) exit(1); while(fgets(line, 100, pp)) fprintf(pout, "%s", line); pclose(pp); pclose(pout); return 0; }

(21)

Duplicazione di processi

#include <stdio.h> #include <sys/fcntl.h>

int main(int argc, char ** argv) {

int i, j, pid; int fin, fout; char ch[8];

fin = open("dati", O_RDONLY); pid = fork();

if(!pid) {

fout = open("uno", O_WRONLY | O_CREAT, 0666); } else {

fout = open("due", O_WRONLY | O_CREAT, 0666); } for(j=0; j<400; j++) { read(fin, ch, 8); write(fout, ch, 8); } }

(22)

Duplicazione di processi

100001

100401

100402

100403

...

100792

100793

100794

100795

100796

100797

100798

100799

100000

100002

...

100391

100392

100393

100394

100395

100396

100397

100398

100399

100400

due

uno

100000

100001

100002

100003

100004

...

100993

100994

100995

100996

100997

100998

100999

dati

(23)

Duplicazione di processi

#include <stdio.h>

int main(int argc, char ** argv) {

int i, j, pid;

FILE * fin, * fout;

fin = fopen("dati", "r"); fscanf(fin, "%d\n", &i); pid = fork(); if(!pid) { fout = fopen("uno", "w"); } else { fout = fopen("due", "w"); } for(j=0; j<400; j++) { fscanf(fin, "%d\n", &i); fprintf(fout, "%d\n", i); } fclose(fout); }

(24)

Duplicazione di processi

100001

100002

100003

...

100124

100125

100126

100127

100512

100513

...

100782

100783

100784

100001

100002

100003

...

100124

100125

100126

100127

100128

100129

...

100398

100399

100400

due

uno

(25)

I/O bufferizzato

• Si utilizza un meccanismo di caching per ridurre il numero di

operazioni di I/O: solo quando il buffer è pieno viene chiesto

l’intervento del sistema operativo e (forse!) scritto su disco

fprintf(f, ...) f=fopen(“file”, ...)

buffer

(26)

Duplicazione di processi / 2

#include <stdio.h> #include <sys/fcntl.h>

int main(int argc, char ** argv) {

int i, j, pid; int fin, fout; char ch[8]; pid = fork();

fin = open("dati", O_RDONLY); if(!pid) {

fout = open("uno", O_WRONLY | O_CREAT, 0666); } else {

fout = open("due", O_WRONLY | O_CREAT, 0666); } for(j=0; j<400; j++) { read(fin, ch, 8); write(fout, ch, 8); } }

(27)

Prestazioni e chiamate di sistema

#include ...

#define BUFFSIZE 8192

int main(void)

{

int n;

char buf[BUFFSIZE];

while( (n=read(STDIN_FILENO,buf, BUFFSIZE))>0)

if (write(STDOUT_FILENO, buf, n) != n) perror("main");

if (n<0) perror("main");

return(0);

}

Note

:

– È corretto usare, come file descriptor:

STDIN_FILENO

e

STDOUT_FILENO

(definiti in

<unistd.h>) al posto di O e 1

(28)

Prestazioni e chiamate di sistema

#include ...

#define BUFFSIZE 8192

int main(void)

{

int n;

char buf[BUFFSIZE];

while( (n=fread(buf, BUFFSIZE, 1, stdin))>0 )

fwrite(buf, sizeof(char), n, stdout);

return(0);

}

(29)

Caching del SO

• Anche il SO usa una sua cache per ridurre il numero di

operazioni di I/O

• Il comando

sync

forza la scrittura su disco

disco 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 cache $ sync --help

Usage: sync [OPTION]

Force changed blocks to disk, update the super block. --help display this help and exit

(30)

Influenza di BUFFSIZE

26.750 13.465 6.848 3.523 1.908 1.062 0.646 0.439 0.334 0.287 0.266 0.227 0.183 0.159 0.133 0.117 0.109 0.118 0.123 0.121 0.123 294.976 148.171 74.518 37.157 18.634 9.370 4.733 2.436 1.240 0.660 0.373 0.238 0.160 0.126 0.116 0.109 0.104 0.114 0.121 0.120 0.121 1 2 4 8 16 32 64 128 256 512 1K 2K 4K 8K 16K 32K 64K 128K 256K 512K 1M fread/fwrite (sec.) read/write (sec.) BUFFSIZE

Test (ambiente UNIX datato):

prog < prova > /dev/null

Riferimenti

Documenti correlati

Potato Tuber Moth meeting - Bologna 2013 Adults. Adult (direct and

(con palline)...

The sources are located on the center of each body panel and the velocity potential satisfies the Laplace equation with the boundary conditions, see 4.22, in all points of the

This approach has been applied to two-dimensional and three-dimensional cases in regular waves: the evaluation of ship mo- tions and added resistance in time domain

Ai sensi di quanto disposto dall’art. la mancanza, l’incompletezza e ogni altra irregolarità essenziale delle dichiarazioni sostitutive previste il concorrente che vi ha

Í read blocca il processo lettore se la pipe è vuota (cioè sospende il processo lettore in attesa di dati) Í write blocca il processo scrittore se non c’è spazio. dentro la pipe

Tossicità per la riproduzione : Non classificato (Basandosi sui dati disponibili i criteri di classificazione non sono soddisfatti). Tossicità specifica per organi bersaglio (STOT)

Hotel Hampton Inn &amp; Suite o similare (trattamento B&amp;B, camera standard tripla) 1 notte Al mattino partirete per Pacuera, dove abborderete sulla nave che vi porterà fino