Actualizado el 21 de Marzo del 2018 (Publicado el 23 de Febrero del 2018)
603 visualizaciones desde el 23 de Febrero del 2018
271,5 KB
36 paginas
Creado hace 18a (23/01/2007)
Tema 9 : Entrada - Salida
Sistemas Operativos:
Programación de Sistemas
Oscar Déniz Suárez
Alexis Quesada Arencibia
Francisco J. Santana Pérez
Curso 2006-07
Introducción
El manejo de la E/S de un sistema operativo es un punto
Los programadores en C en Unix tienen disponibles dos
clave
conjuntos de funciones para acceso a archivos:
Funciones de la librería estándar: printf, fopen...
Llamadas al sistema
Las funciones de librería se implementan haciendo uso
de llamadas al sistema
Aunque las funciones de librería hacen más cómodo el
acceso, las llamadas al sistema proporcionan el tipo de
acceso más directo que puede tener un programa
Introducción
Para el kernel, todo fichero abierto se identifica con un
Los accesos al fichero se realizan usando dicho
Los descriptores sirven en realidad para acceder a
descriptor de fichero
descriptor
cualquier otro componente del sistema que sea capaz
de enviar y recibir datos: dispositivos, sockets,...
Por convención se definen los siguientes descriptores:
0 = entrada estándar
1 = salida estándar
2 = error estándar
Introducción
El kernel mantiene varias estructuras de datos
muy importantes relacionadas con ficheros:
Tabla de descriptores de fichero. Es una
Objetos de ficheros abiertos. Es una estructura
estructura local a cada proceso que indica todos los
ficheros abiertos por un proceso. Cada entrada
apunta a su vez a una entrada en la tabla de ficheros
del sistema.
manejada por el núcleo asociada a cada fichero
abierto en el sistema (puntero de acceso -
desplazamiento de lectura/escritura, etc…)
cada fichero (propietario, permisos, situación del
fichero en disco, …)
Tabla de i-nodos. Guarda información asociada a
Introducción
Tabla de descriptores
de ficheros del proceso A
Objetos de Ficheros
Abiertos
Tabla de i-nodos
Tabla de descriptores
de ficheros del proceso B
Puntero lect/esc
Modo de apertura
Puntero lect/esc
Modo de apertura
Puntero lect/esc
Modo de apertura
Puntero lect/esc
Modo de apertura
Llamadas de E/S
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags).
int open(const char *pathname, int flags, mode_t mode);
mode indica los permisos de acceso (necesario si el fichero se va a crear)
flags puede ser una combinación OR de:
O_RDONLY = Solo lectura
O_WRONLY = Solo escritura Una de estas es obligatoria
O_RDWR = Lectura/escritura
O_CREAT = Crea el fichero si no existe
O_EXCL = Falla si el fichero ya existe (junto con O_CREAT)
O_TRUNC = Trunca el fichero a longitud 0 si ya existe
O_APPEND = Se añade por el final
O_NONBLOCK = Si las operaciones no se pueden realizar sin esperar, volver
O_SYNC = Las operaciones no retornarán antes de que los datos sean físicamente
antes de completarlas
escritos al disco o dispositivo
Llamadas de E/S
#include <unistd.h>
int close(int fd);
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *pathname, int mode);
creat es equivalente a:
open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode)
Cuando un proceso termina todos sus ficheros abiertos son
automáticamente cerrados por el kernel
Llamadas de E/S
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fildes, off_t offset, int whence);
Todo fichero tiene asociado un puntero que marca la posición del siguiente
El puntero se guarda en la tabla de ficheros
La interpretación de offset (que puede ser negativo) depende de whence:
acceso, respecto al principio
SEEK_SET => posicionamiento respecto al inicio del fichero
SEEK_CUR => posicionamiento respecto a la posición actual
SEEK_END => posicionamiento respecto al fin del archivo
lseek devuelve el puntero actual
Si se lleva el puntero más allá del fin del fichero y luego se escribe, el
fichero se hará más grande, rellenando con ceros
Llamadas de E/S
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
count es el nº de bytes a leer
read devuelve el nº de bytes leídos o 0 si
Si p.ej. el fichero tiene 30 bytes e intentamos
estamos al final del fichero
leer 100, read devuelve 30. La próxima vez que
se llame read devuelve 0
Llamadas de E/S
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
nbytes es el nº de bytes a escribir
Si el fichero se abrió con O_APPEND el
puntero del fichero se pone al final del mismo
antes de cada operación de escritura
devuelve el nº de bytes escritos
Llamadas de E/S
#include <unistd.h>
int fsync(int fd);
El sistema puede mantener los datos en memoria por
varios segundos antes de que sean escritos a disco, con
el fin de manejar la E/S más eficientemente
en el disco o dispositivo
fsync hace que se escriban todos los datos pendientes
#include <unistd.h>
int ftruncate(int fd, size_t length);
ftruncate trunca el fichero fd al tamaño length
Llamadas de E/S
#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);
Duplican un descriptor de fichero existente
Se garantiza que el nuevo descriptor devuelto por dup
es el más bajo libre
Con dup2 el valor del nuevo descriptor lo especificamos
en newfd
Tras duplicar, el nuevo descriptor de fichero se refiere al
mismo objeto de fichero abierto que el descriptor original
Por tanto, tras duplicar, ambos tienen los mismos flags
de acceso al fichero, el mismo puntero, etc.
Introducción
Tabla de descriptores
de ficheros del proceso A Objetos de Ficheros
Abiertos
Puntero lect/esc
Modo de apertura
Tabla de i-nodos
Llamadas de E/S
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
Int fcntl(int fd, int cmd, strcut flock *lock)
fcntl cambia las propiedades de un fichero abierto. Puede usarse
para:
Duplicar un descriptor de fichero existente (cmd=F_DUPFD)
Ver/poner el indicador cierre-en-exec (cmd=F_GETFD o F_SETFD)
Ver/poner flags de estado del fichero (cmd=F_GETFL o F_SETFL)
Ver/poner ID de proceso (cmd=F_GETOWN or F_SETOWN)
Ver/poner bloqueos de regiones (cmd=F_GETLK, F_SETLK o
F_SETLKW)
Llamadas de E/S
F_DUPDF => Duplica el descriptor fd,
garantizando que sea el nº más bajo disponible
y que sea mayor o igual que arg. Se devuelve
el nuevo descriptor
F_SETFD => Pone el flag de cierre-en-exec:
Cuando se realiza un exec el descriptor de
fichero se cierra. Por defecto se deja abierto.
F_SETFL => Pone los flags de estado de
fichero a arg. Son los mismos que en la función
open (O_NONBLOCK, O_APPEND,
O_ASYNC)
consistentes los accesos concurrentes a los
ficheros. Se usa para controlar el acceso de
varios procesos a un fichero común
Las operaciones de bloqueo permitidas por
fcntl son:
F_GETLK => Comprueba si una región de un
Llamadas de E/S
El bloqueo de regiones permite hacer
fichero está ya bloqueada. Si es así se sobreescribe
información en el puntero flock
F_SETLK => Bloquea una región de un fichero
F_SETLKW => Versión bloqueante de F_SETLK
Llamadas de E/S
struct flock {
short l_type; /* Tipo bloqueo: F_RDLCK, F_WRLCK, F_UNLCK */
short l_whence; /* Cómo interpretar l_start : SEEK_SET,
SEEK_CUR, SEEK_END */
off_t l_start; /* Offset de comienzo del bloqueo */
off_t l_len; /* Número de bytes a bloquear, si 0 bloquea hasta final del
fichero */
pid_t l_pid; /* PID del proceso que bloquea la región (solo F_GETLK)
*/
};
Valores de flock.l_type:
F_RDLCK indica bloqueo de lectura
F_WRLCK indica bloqueo de escritura
F_UNLCK desbloquea
Llamadas de E/S
El éxito del bloqueo de una región depende de si ya está
bloqueada por otro proceso:
Región tiene
Petición bloq.
lectura
OK
Petición bloq.
escritura
OK
OK
Denegada
Denegada
Denegada
Ningún
bloqueo
1 o más
lectura
bloqueos de
1 bloqueo de
escritura
Llamadas de E/S
El fichero /proc/locks contiene
bloqueo de un fichero
información sobre los bloqueos de
regiones que tienen actualmente los
ficheros abiertos
Cada línea representa información de
Llamadas de E/S
Ejercicio práctico:
Vamos crear un proceso que lee o escribe en un
fichero en función de un parámetro que pasamos
como argumento mediante la línea de órdenes (l-
lector, e- escritor). Las operaciones de lectura y
escritura se realizarán un número de veces N
indicado también mediante la línea de órdenes. La
escrituras consistirán en el incremento del valor
entero almacenado en el archivo. Tanto las N
lecturas como las N escrituras se deberán realizar
en bloque (de forma atómica) y bajo control del
usuario, que hará efectiva cada operación de
lectura/escritura pulsando “enter”.
Llamadas de E/S
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
stat devuelve una estructura de información de un fichero
fstat hace lo mismo pero a partir de un fichero abierto
lstat es para enlaces simbólicos (si se llama a stat para un enlance
simbólico se devuelve información del fichero al que apunta el
enlace, pero no del enlace mismo)
ls -l
La información de stat es similar a la que devolvería el comando
Llamadas de E/S
struct stat
{
dev_t st_dev;
ino_t st_ino;
mode_t st_mode;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
dev_t st_rdev;
off_t st_size;
unsigned long st_blksize;
unsigned long st_blocks;
time_t st_atime;
time_t st_mtime;
time_t st_ctime;
};
/* device (major and minor numbers) */
/* inode */
/* protection and type of file */
/* number of hard links */
/* user ID of owner */
/* group ID of owner */
/* device type (if inode device) */
/* total size, in bytes */
/* blocksize for filesystem I/O */
/* number of blocks allocated */
/* time of last access */
/* time of last modification */
/* time of last change */
Llamadas de E/S
Tipos de ficheros en UNIX:
Fichero regular. El kernel no distingue si es de texto o con
Directorio. Un fichero que contiene los nombres de otros
datos binarios
ficheros y punteros a la información en los mismos. Cua
Comentarios de: Tema 9 - Entrada-Salida - Sistemas Operativos: Programación de Sistemas (0)
No hay comentarios