Upload
dangbao
View
234
Download
0
Embed Size (px)
Citation preview
3.2.1
3.2: Chiamate di Sistema Unix/Linux● Introduzione
● Gestione dei canali di I/O
● Gestione dei file
● Controllo dei processi
● Pipe e FIFO
● Ambiente di lavoro dei processi
● Gestione dei segnali
● System V IPC
● Altre chiamate
3.2.2
Introduzione● Chiamate sistema Unix = funzioni C.
● Valore di ritorno: -1 in caso di errore, 0 se O.K. (salvo ove diversamente specificato)
● Variabile errno : #include <errno.h>
extern int errno;
● Funzioni di libreria strerror() e perror():char *strerror(int errnum);
void perror(char *errstring);
strerror() restituisce messaggio esplicativo del valore di errnum; perror() stampa a stderr errstring seguita da messaggio esplicativo di errno.
● Si veda intro(2), perror(3).
3.2.3
Introduzione (Cont.)● Inclusione tipica degli header file:
#include <sys/types.h> /* pseudo-tipi */
#include <unistd.h>
#include <stdlib.h>
● pseudo-tipi utilizzati:typedef long time_t;
typedef long off_t;
typedef unsigned int size_t;
typedef short pid_t;
...
3.2.4
Gestione dei canali di I/O
● int creat(const char *path, mode_t mode);– mode = bit di protezione; modificato da umask(2)– ritorna file descriptor (f.d.) del file creato– il file è aperto in sola scrittura– es.:
fd = creat("/tmp/tmpfile", 0600);● #include <fcntl.h>
int open(const char *path, int flags, mode_t mode);– path e mode: come per creat(2)– flags: O_RDONLY, O_WRONLY, O_RDWR;
O_APPEND, O_CREAT, O_TRUNC, O_EXCL– mode è facoltativo; è usato (obbligatoriamente) solo se c'è O_CREAT– ritorna file descriptor (f.d.) del file aperto– creat(path, mode) equivale a
open(path, O_CREAT|O_WRONLY|O_TRUNC, mode)– es.:
fd = open("./my_data", O_RDWR);
3.2.5
Gestione dei canali di I/O (Cont.)● int close(int fd);
– fd = f.d. del file da chiudere
● int read(int fd, char *buf, size_t nb);– legge fino a nb byte dal canale identificato da fd e li scrive a partire da buf– ritorna il numero di byte effettivamente letti (<= nb), 0 se EOF, -1 se errore– es.:
nn = read(fd, buf, BUFSIZ);
● int write(int fd, const char *buf, size_t nb); – scrive nb byte sul canale identificato da fd, leggendoli a partire da buf– ritorna il numero di byte effettivamente scritti– es.:
nn = write(fd, buf, BUFSIZ);
3.2.6
Gestione dei canali di I/O (Cont.)
● off_t lseek(int fd, off_t offset, int whence);– sposta l'I/O pointer (offset del prossimo read o write)– whence: SEEK_SET, SEEK_CUR, SEEK_END– offset: può essere negativo– ritorna nuovo valore dell'I/O pointer; (off_t)-1 se errore– seek oltre EOF 'buco' (zona letta come tutti 0, ma non occupa spazio
fisico)– es.:
ptr = lseek(fd, (off_t)-1024, SEEK_END);
● off_t tell(int fd);– restituisce il valore attuale dell'I/O pointer, senza modificarlo– equivale a
lseek(fd, (off_t)0, SEEK_CUR);
3.2.7
Gestione dei canali di I/O (Cont.)
● int dup(int oldfd);int dup2(int oldfd, int newfd);
– associa a un f.d. aperto un nuovo f.d., clone del precedente– ritornano il nuovo f.d.– dup() sceglie il nuovo f.d. come il più piccolo disponibile– dup2() chiude prima newfd, se è già in uso– il nuovo e il vecchio f.d. condividono modo di apertura, I/O pointer, etc.– es.: ridirezione di stdout su un file
int fd;
if((fd = open("outfile", O_WRONLY|O_CREAT, 0666)) == -1)error_exit("...");
dup2(fd, 1); /* N.B. - 1 è il f.d. dello stdout */close(fd);
3.2.8
Gestione dei File● int link(const char *oldpath, const char *newpath);
– hard link– crea nuovo link (nuovo alias) per un file (normale o speciale)– oldpath e newpath devono essere nello stesso file-system; oldpath deve
esistere, e non può essere una directory– esiste limite massimo al numero di hard link di un file, che è memorizzato
nell'i-node (di solito 128)– dopo l'operazione, oldpath e newpath sono indistinguibili– ritorna 0 se OK, -1 se errore
● int symlink(const char *oldpath, const char *newpath);– symbolic link– crea link simbolico (nuovo alias) per un file (normale o speciale o directory)– oldpath e newpath possono non appartenere allo stesso file-system; oldpath
può non esistere, e può anche essere una directory– ritorna 0 se OK, -1 se errore
3.2.9
Gestione dei File (Cont.)
● int unlink(const char *path);– rimuove un hard link per il file:
● decrementa link count nello i-node● libera la entry della directory
– se il link era l'ultimo (link count scende da 1 a 0), il file è rimosso (blocchi di dati e i-node deallocati)
– es.: rinomina di un filelink("pippo", "pluto");unlink("pippo");
● int truncate(const char *path, off_t length);int ftruncate(int fd, off_t length);
– il file identificato da path o da fd è troncato; la sua dimensione è al massimo di length byte (eventuali dati oltre length vengono persi)
– con ftruncate(), il file deve essere aperto in scrittura
3.2.10
Gestione dei File (Cont.)
● int access(const char *path, int mode);– verifica la possibilità di accesso ad un file, da parte del processo– mode: R_OK, W_OK, X_OK, F_OK (o una combinazione di questi, con
bitwiseOR)– es.:
if(access("file", R_OK|W_OK) == 1)printf("cannot open file in RDWR mode\n");
● #include <sys/stat.h>int chmod(const char *path, mode_t mode);int fchmod(int fd, mode_t mode);– cambia i bit di protezione di un file, dato un path o un fd– es.:
fchmod(fd, 0600);● int chown(const char *path, uid_t uid, gid_t gid);
int fchown(int fd, uid_t uid, gid_t gid);– cambia proprietario e gruppo di un file– uid e gid vanno specificati come valori numerici
3.2.11
Gestione dei File (Cont.)● #include <sys/stat.h>
int stat(const char *path, struct stat *buf);int lstat(const char *path, struct stat *buf);fstat(int fd, struct stat *buf);– restituisce stato dell'inode di un file, dato un path o un fd– lstat() si riferisce al file link simbolico (se è il caso), non a quello puntato– retval == 1 errno == ENOENT il file non esiste– struct stat {
dev_t st_dev; /* device */ ino_t st_ino /* inode number */ umode_t st_mode; /* file type + setUID etc. + protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device type (if special file) */ off_t st_size; /* total size, in bytes */ ... time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last change */};
3.2.12
Gestione dei File (Cont.)● sys/stat.h definisce vari simboli e macro applicabili al membro st_mode
(v. stat(2)):
– S_ISREG(m), S_ISDIR(m), S_ISCHR(m), etc.
● Vero se il file è un file regolare, una directory, uno special file di tipo carattere, etc.
– S_IFMT
● Bit mask per isolare il tipo di file
– S_ISUID, S_ISGID, ISVTX, etc.
● Bit set-UID, set-GID, sticky bit, etc.
3.2.13
Controllo dei Processi● pid_t fork(void);
– crea nuovo processo (child figlio), duplicando quello originale (parent padre)
– ritorna● al figlio: (pid_t)0● al padre: il PID del figlio appena creato● in caso di errore, (pid_t)1 (al padre)
– il processo figlio eredita tutto l'ambiente del padre, compresi i canali aperti (tutto tranne il PID)
– il figlio si trova come se avesse eseguito tutto il programma fino al fork, come il padre
– es.:if(pid = fork()){ /* padre */
if(pid == (pid_t)1) { perror("fork"); exit(1); }...
} else {/* figlio */...
}● Linux supporta i kernel threads con la chiamata clone(2)
3.2.14
Controllo dei Processi (Cont.)● int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);int execv(const char *path, char *const argv[]);int execvp(const char *file, char * const argv[]);– sostituisce, nel processo corrente, un nuovo programma all'attuale, e lo
esegue– il processo rimane lo stesso, quindi tutto l'ambiente è inalterato– execlp() ed execvp() usano la variabile di environment PATH per cercare il
file– execl(), execlp(): arg e gli argomenti successivi sono arg0, arg1, etc.; l'ultimo
argomento deve essere un NULL pointer– execv(), execvp(): argv è un array già nel formato atteso dalla function
main()– sono in realtà tutti frontend di un'unica system call, execve(2)– 'viaggio senza ritorno': se c'è un valore di ritorno, è 1 (impossibile eseguire
il nuovo programma)– es.:
execl("/bin/cat", "cat", "/tmp/tmpfile", NULL); printf("cannot execute program!\n");
3.2.15
Controllo dei Processi (Cont.)● void exit(int code);
– termina il processo– flush dell'I/O pending (stdout etc.), chiude tutti i file, esce– non ritorna mai
● #include <sys/wait.h>pid_t wait(int *status_addr);– aspetta finchè uno dei processi figli termina– ritorna il PID del primo figlio che ha terminato– se status_addr non è NULL, ritorna anche, nell'intero puntato, lo stato
d'uscita del figlio:● exit code● segnale che ha eventualmente terminato il processo, e altre
informazioni– lo stato d'uscita può essere analizzato con le macro WEXITSTATUS(),
WIFEXITED(), WIFSIGNALED(), WTERMSIG(), WCOREDUMP() e altre vedere wait(2)
– variante: waitpid(2)– es.:
while(wait(NULL) != (pid_t)1); /* wait for all children */
3.2.16
Controllo dei Processi (Cont.)● Combinazione tipica delle chiamate viste:
pid_t pid;int exstatus, excode;
if(pid = fork()){
/* processo padre */if(pid == (pid_t)1)
error_exit("cannot fork\n");...while(wait(&exstatus) != pid && pid != (pid_t)1)
;excode = WEXITSTATUS(exstatus);exit(excode); /* esce col codice del figlio */
}else{
/* processo figlio *//* ... eventuale ridirezione dell'I/O */execl("/usr/local/bin/program", "program", "x", "file", NULL);error_exit("cannot exec program\n");
}
3.2.17
Pipe e FIFO
● Costituiscono il meccanismo più semplice di comunicazione interprocesso
● int pipe(int fdc[2]);– stabilisce un canale di comunicazione tra processi, che può essere
condiviso con i processi figli– il canale è unidirezionale– fdc[0] serve per leggere dal pipe, fdc[1] per scrivere– il pipe è implementato come un file anonimo, di lunghezza massima fissa (di
solito pari a 4 Kbyte), con seek impliciti per comportamento da FIFO– sincronizzazione automatica di processi scrittori e lettori in caso di pipe
pieno/vuoto– EOF (0 byte letti) ritornato dalla read() al lettore se non c’è più nessuno
scrittore– SIGPIPE inviato allo scrittore per una write() se non c’è più nessun lettore– è fondamentale orientare il pipe prima di utilizzarlo
3.2.18
Pipe e FIFO (Cont.)
● FIFO = pipe con nome (named pipe), che esiste in modo permanente.
● mknod(2) = creazione di special file, FIFO e altro. Relativamente complicata da utilizzare.
● mkfifo(3) = funzione di libreria (specifica POSIX).● #include <sys/stat.h>
int mkfifo(const char *path, mode_t mode);– crea un FIFO
– comportamento identico a quello di un pipe, salvo che il file non è anonimo
– un processo che apre il FIFO in scrittura resta bloccato sulla open(2) finchè un altro lo apre in lettura, e viceversa
– se mode contiene altri bit oltre quelli di protezione, il loro significato è “implementation-defined” (POSIX).
3.2.19
Ambiente di lavoro dei processi● int chdir(const char *path);
● int chroot(const char *path);
– cambia la directory di lavoro (chdir) o la directory radice (chroot) del processo
● pid_t getpid(void);
● pid_t getppid(void);
– restituisce il proprio PID (getpid), o quello del proprio processo padre (getppid)
● uid_t getuid(void);
● uid_t geteuid(void);
● gid_t getgid(void);
● gid_t getegid(void);
– restituisce lo user-ID reale (getuid) o effettivo (geteuid), ovvero il group-ID reale (getgid) o effettivo (getegid) del processo
3.2.20
Ambiente di lavoro dei processi (Cont.)● int setuid(uid_t uid);
● int setgid(gid_t gid);
– stabilisce un nuovo userID (setuid) o un nuovo groupID (setgid) per il processo
– normalmente riservate al superuser
– N.B. fare prima setgid(), poi setuid()
● int umask(int mask);
– nuova maschera di creazione dei file
– mask: in open(2), creat(2), mkfifo(3) il vero modo è dato da mode & ~umask● int nice(int incr);
– incrementa priorità numerica del processo
– priorità: 0 (alta) ÷ 40 (bassa); default: 20
– root puo` specificare incr negativo (alzare la priorità)● N.B. v. anche getenv(3), putenv(3), in “Altre chiamate”
3.2.21
Gestione dei segnali● Segnale: provoca interrupt software nel processo ricevente
● Azione di default all’interrupt: a) exit b) core-dump + exit [*]
● Segnali principali (vedi signal(2)):
– SIGHUP (1) terminale chiuso o scollegato
– SIGINT (2) intr char. da terminale
– SIGQUIT (3) quit char. da terminale [*]
– SIGILL (4) istruzione illegale
– SIGKILL (9) terminazione forzata (non intercettabile)
– SIGSEGV (11) violazione spazio memoria [*]
– SIGPIPE (13) scrittura in pipe senza processo lettore
– SIGALRM (14) orologio allarme scaduto
– SIGTERM (15) terminazione software (default per kill(1))
– SIGCHLD (17) morte di un processo figlio
– SIGUSR1, SIGUSR2 (10, 12) – userdefined
● Linux supporta anche segnali detti real-time (sono accodati).
3.2.22
Gestione dei segnali (Cont.)● #include <signal.h>
int kill(pid_t pid, int sig);
– invia il segnale sig al processo con PID pari a pid
– processo ricevente: deve avere stesso UID del processo mittente (salvo se mittente è root)
– se pid == -1: invia segnale a tutti i processi (eccetto a init(8), PID == 1)
– se pid < -1: invia segnale al process-group -pid (PID del process-group leader, ovvero primo processo che ha aperto il terminale di controllo)
– es.:
/* processo suicida; lascia core dump ai posteri */
kill(SIGQUIT, getpid());
3.2.23
Gestione dei segnali (Cont.)● #include <signal.h>
void (*signal(int sig, void (*handler)(int)))(int);– alla ricezione di sig, viene eseguita la routine di interrupt puntata da handler
– handler == SIG_DFL: viene (re)installata azione di default
– handler == SIG_IGN: il segnale viene ignorato
– retval = valore precedente di handler per quel segnale
– (*handler)() è chiamato con un argomento: segnale che ha generato l’interrupt
– ad ogni interrupt, l’azione installata è resettata a SIG_DFL; (*handler)() deve eventualmente richiamare signal(2) per reinstallare la routine
– segnale arriva durante una sys.call lenta (read(2) da tty, wait(2), pause(2) etc. processo in attesa di evento): ritorno prematuro, retval == 1, errno == EINTR
– processo che non aspetta (wait(2)) i suoi figli (es. tipico: server concorrente): per evitare di lasciarli in ZOMBIE state, deve ignorare SIGCHLD:
signal(SIGCHLD, SIG_IGN);/* avoid zombie children */
3.2.24
Gestione dei segnali (Cont.)● Uso tipico della chiamata signal(2):
#include <signal.h>
void trap_intr(int); /* signal interrupt routine */
void (*fp)(int); /* a function pointer */
…
fp = signal(SIGTERM, trap_intr);
/* critical code */
…
/* end of critical code */
signal(SIGTERM, fp); /* reinstall previous action */
…
void trap_intr(int sig)
{
signal(sig, trap_intr); /* handle receipt of all subsequent interrupts */
…
}
● Variante: sigaction(2), sigprocmask(2), sigpending(2), sigsuspend(2)
3.2.25
Gestione dei segnali (Cont.)● int pause(void);
– sospende processo, per sempre (o fino a ricezione di segnale)
– il processo va a dormire; non consuma CPU
● unsigned alarm(unsigned sec);
– invia il segnale SIGALRM al processo corrente dopo sec secondi
– risoluzione: 1 secondo
– alarm(0) resetta il meccanismo
– retval: numero di secondi mancanti al termine dell’eventuale alarm precedente
– es.: read from serial line or socket, with timeout
signal(SIGALRM, timeout);
alarm(10); /* 10 seconds max. time */
nn = read(fd, buf, BUFSIZ);
alarm(0); /* reset timeout */
if(nn == -1) {
if(errno == EINTR) printf(“read timeout expired\n”);else error_exit(“read error\n”);
}
3.2.26
Gestione dei segnali (Cont.)● unsigned sleep(unsigned sec);
– funzione di libreria
– sospende processo per sec secondi
– retval: 0 se tempo scaduto, n. di secondi restanti se ritorno prematuro
– implementata con signal(2) + alarm(2) + pause(2)
3.2.27
IPC di System V● Gli IPC risolvono alcune limitazioni degli altri meccanismi di
comunicazione tra processi:
– i pipe sono limitati a processi con relazione di parentela
– i FIFO non risolvono bene lo scambio dati tra più di 2 processi
● Ogni oggetto IPC è un oggetto permanente:
– vive anche dopo la terminazione del processo che lo ha creato
– occupa spazio nell’indirizzamento virtuale del kernel
– è swappabile
● Ogni oggetto IPC ha un nome unico: chiave (key), intero positivo.
● La chiave si alloca con la funzione di libreria ftok(3):# include <sys/types.h># include <sys/ipc.h>key_t ftok ( char *pathname, char proj )
– genera chiave unica in funzione del pathname di un file e di un identificativo di progetto, proj.
3.2.28
IPC di System V (Cont.)
● Analogia file - IPC:– nome (char string) ↔ chiave (long int)– file descriptor (int) ↔ identificatore (int)– inode (data struct.) ↔ descriptor (data struct):
msqid_ds, shmid_ds, semid_ds
● Operazioni di base su oggetti IPC:– get() ↔ open(), creat() -- id = get(key);– ctl() ↔ ioctl(), unlink() -- ctl(id);– op() ↔ read(), write(), etc. -- op(id);
read, write mesg.
attach, detach shm.
modify sem.
3.2.29
IPC di System V (Cont.)
● Flags per get() e ctl():– IPC_CREAT, IPC_EXCL; IPC_NOWAIT
● comandi per ctl():– IPC_RMID (distruz.), IPC_SET (modifica caratteristiche), IPC_STAT
(leggi statistiche)● Gli oggetti IPC esistenti possono essere controllati con ipcs(8) e
rimossi con ipcrm(8).
3.2.30
Code di Messaggi
● Mantengono memorizzati messaggi in modo permanente, finchè un processo li estrae dalla coda.
● # include <sys/ipc.h>#include <sys/msg.h>int msgget(key_t key, int flag);
– crea coda di messaggi, data una chiave key
– restituisce l’identificatore (id)
– flag: bit di protezione (es. 0660), OR-ed con IPC_CREAT, IPC_EXCL (errore se l’oggetto esiste già)
● int msgctl(int id, int cmd, struct msqid_ds *buf);
– id: identificatore (restituito da msgget())
– cmd: IPC_RMID -> distruggi la coda; buf è ignorato
– retval: 0 (OK) o -1 (errore).
3.2.31
Code di Messaggi (Cont.)
● int msgsnd(int id, const void *msg, size_t size, int flag);
– invia un messaggio in una coda
– id: identificatore della coda
– msg: punta a una struttura del tipostruct msgbuf {
long mtype; /* tipo messaggio (>= 0) */char mtext[MSIZE]; /* messaggio, max. MSIZE car. */
};– size: numero byte in mtext[ ] da trasferire
– flag: 0 o IPC_NOWAIT → se la coda è piena, non sospendere processo ma ritorna in errore
– nel messaggio viene memorizzato sia msg->mtype (4 byte) che msg->mtext[ ] (size byte)
– retval: 0 (OK) or -1 (error).
3.2.32
Code di Messaggi (Cont.)
● int msgrcv(int id, void *msg, size_t size, long type, int flag);
– estrae un messaggio da una coda
– id: identificatore della coda
– msg: punta a una struttura di tipo msgbuf (v. slide precedente)
– size: numero max. di byte da trasferire in msg->mtext[ ] (oltre ai 4 byte di msg->mtype, trasferiti comunque)
– type: tipo messaggio (in msg->mtype)● type > 0 estrai un messaggio di tipo type● type = 0 estrai qualunque messaggio● type < 0 estrai messaggio di tipo <= -type, scegliendo
in ordine crescente di tipo (dal più basso)– i messaggi vengono estratti in ordine di inserzione (dapprima i più vecchi)
– flag: 0 o IPC_NOWAIT → se la coda è vuota (rispetto al tipo di messaggio voluto), non sospendere processo ma ritorna in errore
– retval: numero di byte copiati in msg->mtext[ ], o -1 (errore).
3.2.33
Memoria Condivisa
● Una zona di memoria condivisa (shared memory) va creata, quindi collegata al proprio spazio di indirizzamento da parte di uno o più processi, e infine usata; per usarla non occorre nessuna chiamata particolare, basta accedere alla memoria stessa.
● # include <sys/ipc.h>#include <sys/shm.h>int shmget(key_t key, int size, int flag);
– crea memoria condivisa, grande size byte, data una chiave key
– restituisce l’identificatore (id)
– flag: come per msgget()
● int shmctl(int id, int cmd, struct shmid_ds *buf);
– id: identificatore (restituito da shmget())
– cmd: IPC_RMID -> distruggi la memoria; buf è ignorato
– retval: 0 (OK) o -1 (errore).
3.2.34
Memoria Condivisa (Cont.)
● void *shmat(int id, void *addr, int flag);
– collega una memoria condivisa al proprio spazio di indirizzamento
– id: identificatore
– addr: indirizzo a cui si vuole collegare; se è NULL, sceglie il sistema
– flag: specifica modalità di accesso● SHM_R, SHM_W, SHM_RW - read, write, read-write
– retval: indirizzo effettivo di collegamento, o (void *)-1 (errore)
● int shmdt(const void *addr);
– scollega una memoria condivisa
– addr: indirizzo della memoria da scollegare
– retval: 0 (OK) o -1 (errore).
3.2.35
Semafori
● Ciascun oggetto IPC semaforo implementa un array di semafori, i cui elementi possono essere modificati (operazioni signal e wait) tutti insieme in modo atomico.
● # include <sys/ipc.h>#include <sys/sem.h>int semget(key_t key, int nsems, int flag);
– crea semaforo, con nsems elementi, data una chiave key
– restituisce l’identificatore (id)
– flag: come per msgget()
3.2.36
Semafori (Cont.)● int semctl(int id, int semnum, int cmd, union semun arg);
– serve per
● rimuovere semaforo● assegnare valore iniziale, leggere valore attuale
– id: identificatore (restituito da semget())
– arg: la union è fatta così:
union semun {
int val;ushort *array;
};– cmd:
● IPC_RMID: distruggi il semaforo; gli altri parametri sono ignorati● GETVAL: retval = valore dell’elem. n. semnum del semaforo● SETVAL: assegna arg.val all’elem. n. semnum del semaforo● GETALL: leggi valori di tutti gli elementi e copiali in arg.array● SETALL: copia i valori di tutti gli elementi da arg.array
– retval: (salvo il caso GETVAL): 0 (OK) o -1 (errore).
3.2.37
Semafori (Cont.)
● int semop(int id, struct sembuf *sops, unsigned nsops);
– implementa operazioni di increm./decrem. (signal / wait) su nsops elementi di un semaforo
– id: identificatore (restituito da semget())
– sops: punta ad array di nsops struct così fatte:
struct sembuf {ushort sem_num; /* elem. su cui operare */short sem_op; /* operazione */short sem_flag; /* opzioni (0 o IPC_NOWAIT) */
};– sem_op è un valore da sommare algebricamente al valore dell’elemento del
semaforo (sem_val):
3.2.38
Semafori (Cont.)
● a) sem_op < 0 : allocazione risorsa (wait)
if(semval >= abs(sem_op)) { semval -= abs(sem_op); return OK; } else { if(sem_flg & IPC_NOWAIT) return -1; else { wait till semval >= abs(sem_op); semval -= abs(sem_op); return OK; } }
● b) sem_op > 0 : liberazione risorsa (signal)
semval += sem_op; return OK;
● c) sem_op == 0 : attesa di semaforo nullo
if(semval == 0) return OK; else { if(sem_flg & IPC_NOWAIT) return -1; else { wait till semval == 0; return OK; } }
3.2.39
Altre chiamate● #include <sys/times.h>
clock_t times(struct tms *buf);
– struttura tms : definita come segue
struct tms
{
time_t tms_utime; /* user time */
time_t tms_stime; /* system time */
time_t tms_cutime; /* user time of children */
time_t tms_cstime; /* system time of children */
};– ritorna in *buf tempo CPU in user- e system (kernel)-mode, per processo e
per i figli terminati (cumulato)
– tempi espressi in clock ticks del sistema (di solito 10 msec.)
● Il valore può essere ottenuto tramite sysconf(3):
ticks_per_second = sysconf(_SC_CLK_TCK);– retval: tempo dal bootstrap (istante arbitrario - usare solo per differenze)
3.2.40
Altre chiamate (Cont.)
● time_t time(time_t *timep);
– retval: data e ora attuale (n. di secondi dal 1/1/1970, 00:00, GMT)
– se timep non è NULL, ritorna stesso valore anche lì
– N.B. - l’ora interna e` sempre quella di Greenwich; il valore ritornato da time(2) va poi scalato secondo time-zone (vedi ad es. localtime(3))
– variante: gettimeofday(2)● #include <sys/wait.h>
int system(const char *cmd);
– funzione di libreria, implementata con fork(2) + exec(2) + wait(2) + sh(1)
– cmd: shell command line (con metacaratteri, etc.)
– retval: process exit status, ritornato da wait(2) (e non lo exit code)
– es.:
xs = system(“cc -o prog *.c >cc.LOG 2>&1”);exit(WEXITSTATUS(xs));
3.2.41
Altre chiamate (Cont.)
● char *getenv(const char *var);
int putenv(const char *string);
– funzioni di libreria per gestione environment
– environment: array di puntatori a stringhe, identico ad argv di main()
extern char **environ;– ogni stringa è del tipo “var=string”
– getenv(3): retval = valore della variabile di envir. var, o NULL se non è definita
– putenv(3) inserisce una variabile di environment (sostituendo eventuale valore precedente); retval = 0 se OK, -1 se errore
– es.:
char *home = getenv(“HOME”);
putenv(“USERNAME=luca”);