Funzioni C

Quelle che sono qui brevemente commentate, in forma schematica, sono alcune funzioni di libreria C di UNIX, in particolare il materiale è tratto dalle manpage delle sezioni 2 e 3 della libreria libc GNU di Linux.
Ringrazio infinitamente il root di chiara per aver messo a disposizione all'interno del dipartimento un gate man2html che mi ha permesso di fare solo qualche link, evitando la duplicazione del materiale.

La differenza sostanziale tra System Calls e Function Calls sta nella specificità di queste funzioni che devono interagire con il sistema operativo e con alcuni dei suoi aspetti; in breve le System Calls sono delle Function Calls speciali perchè fanno riferimento a funzioni di sistema di UNIX e non a generiche funzioni implementate da generiche librerie e/o definite dall'utente.

File I/O

Tutte queste funzioni hanno come scopo quello di stabilire una corrispondenza tra un file su disco (o una pipe) e un descrittore, ovvero quella struttura dati che all'interno del linguaggio C viene utilizzata per gestire (accedere e manipolare) i file stessi, e le operazioni (ovvie) su questi descrittori di file. Un descrittore solitamente e` un semplice intero non negativo.

int open(const char *pathname,  int flags) open cerca di ``aprire'' un file, il cui percorso sul disco è dato dalla stringa pathname, ovvero di associare al file stesso un descrittore, e se ci riesce ritorna il descrittore stesso, altrimenti ritorna un numero negativo (-1 per la precisione); flags è un intero che permette di scegliere la modalità di apertura dello stesso (readonly, writeonly, readwrite)
ssize_t read(int fd,  void *buf,  size_t count) read cerca di leggere fino a count bytes dal file descriptor fd e mettendo i bytes letti nel buffer buf; ritorna il numero di bytes letti (equivalente al numero di posizioni in cui si è avanzati nel file), solitamente un valore minore o ugiuale a count; se zero ci si considera a fine file, se negativo c'è stato un errore e non è possibile determinare di quanto si è spostata la posizione sul file
ssize_t write(int fd,  const void *buf, size_t count) write cerca di scrivere fino a count bytes sul file descriptor fd prelevando i bytes dal buffer buf; ritorna i bytes effettivamente scritti oppure -1 se si è verificato un errore
int dup(int oldfd) dup semplicemente duplica il file descriptor del file oldfd; è da notare che il nuovo e il vecchio file descriptor possono essere usati indistintamente, visto che i due descrittori condividono tutte le risorse (lock, posizione del puntatore e flags)
int stat(const char *file_name,  struct stat *buf) stat ritorna delle informazioni sul file il cui percorso è dato dalla stringa file_name, riempiendo appositamente la struttura dati buf (che comprende tutte le infromazioni utili su un file UNIX come device, inode, gruppo, owner, permessi, tempi di accesso, ...); non occorre avere i permessi di accesso al file in questione, ma solo alla directory in cui risiede (come è tradizione UNIX); inoltre esiste anche fstat che fa la stessa cosa ma su un file descriptor
int chmod(const char *path,  mode_t mode) chmod permette di cambiare i permessi del file il cui percorso è dato dalla stringa path al nuovo valore mode, che è ottenunto sommando in or logico una serie di flag (in pratica è con la stessa sintassi dei bit di permesso che si usano anche nel normale comando chmod(1)); chiaramente il processo che tenta questa operazione deve avere sufficienti permessi per poterla portare a termine; ritorna 0 se l'operazione ha avuto successo, -1 altrimenti

Funzioni associate ai processi

Ogni processo in UNIX ha un descrittore (PID, o Process IDentifier) e delle relazioni con altri processi (suo padre, o i suoi figli).
Inoltre ogni processo UNIX è influenzato da segnali, ovvero da ``messaggi'' che i vari processi si possono passare attraverso un meccanismo noto e condiviso; ogni processo, ricevuto un segnale, può inziare una routine di gestione oppure ignorarlo (a meno di certi segnali predefiniti che hanno routine di gestione predefinite e che non possono essere ignorati).
Questo insieme di funzioni permette di gestire tutte le operazioni che possono essere fatte sui PID stessi, ovvero creazione, creazione di un figlio, distruzione, controllo dei figli.

pid_t fork(void) fork crea un processo figlio che differisce dal padre solo per il suo PID (è un nuovo processo) e per il suo PPID (Parent PID, infatti è uguale al processo che ha chiamato fork() stessa); lock sui file e segnali pendenti non vengono ereditati; ritorna il PID del nuovo processo creato o -1 se c'è stato un errore
void exit(int status) exit provoca la chiusura del programma che lo ha eseguito, e forza il valore di ritorno del programma stesso a status; tutti i file aperti sono aggiornati e poi chiusi
pid_t wait(int *status) wait sospende l'esecuzione del processo corrente fino a che uno dei suoi figli non sia terminato o fino a che non arrivi un segnale che comporti la terminazione del processo corrente o comunque l'esecuzione di una routine di gestione del segnale in questione; se il figlio era già uscito al momento della chiamata di wait (processo zombie) wait non fa nulla; se status non è null, wait lo usa per segnalare il valore di ritorno del figlio appena terminato; wait ritorna il PID del processo figlio di cui ha aspettato la terminazione, o -1 se ci sono stati errori
int exec{l,lp,le,t,v,vp}(  const char *path,  const char *arg, ...) la famiglia di funzioni exec sostituisce all'immagine del processo correntemente in esecuzione (quello che la ha chiamata) un nuovo processo ottenuto dal file il cui percorso è dato da path passandogli come parametri le stringhe arg; quello che differenzia realmente le varie exec è proprio il meccanismo di passaggio dei parametri; da come è strutturata non dovrebbe mai ritornare nulla, ritorna -1 se c'è un errore.
pid_t getpid(void) getpid ritorna il valore del PID corrente; getppid ritorna il PID del padre del processo corrente

Corso di reti di Calcolatori Ritorna alla pagina del corso di Reti di Calcolatori