Documentos de Académico
Documentos de Profesional
Documentos de Cultura
SistemasOperativos
Prctica7:
ProgramacindeSistemas
(SystemProgramming:I/O)
Objetivo
En esta prctica nos enfocaremos en los elementos bsicos para el desarrollodeaplicaciones
para ambiente GNU/Linux utilizando el lenguaje nativo del mismo: C. Nos enfocaremos
principalmenteendiferenciarelusodecdigodeusuarioycdigodesistema.
ndice
DesarrollodeprogramasusandoProgramacindesistemas
Algunasllamadasasistema
Lecturamedianteread()
Escribiendoconwrite()
Cerrararchivos
Unejemplodellamadasalsistema
FileI/O:writeback,SynchronizedI/O
SynchronizedI/O
Lecturaspredictivas
I/Ousandobuffers(lenguajeCestndar)
Apuntadoraarchivo
LeyendoStreams
Escribiendoaunstream
LabibliotecaestndardeCimplementavariasfuncionesparaescribirenunstream
abierto.
EjemplodeunprogramaqueusaI/Oenbuffers.
MapeoaMemoria(Memorymap)
Referencias
Fuentesadicionales
DesarrollodeprogramasusandoProgramacindesistemas
Laboratoriode
SistemasOperativos
Ejemplosdesoftwaredesistemaincluyen:
Elsistemaoperativo
Losinterpretadoresdecomandos
Lossistemasdeinterfacegrfica
Los compiladores, ensambladores, controladores de versin, los depuradores,
etc.
Programacin de Aplicaciones (
Application Programmin
g
)
: es el arte de escribir
software de Aplicaciones. Un
software de aplicacin es un programa autocontenido
querealizaunafuncinespecficadirectamenteconelusuario.
Ejemplosincluyen:
Hojasdeclculo(i.e.Excel)
Softwareparaprocesamientodetexto(i.e.Office)
SoftwareparaPresentacin(i.e.PowerPoint)
Aplicacionesderedcomocorreoelectrnico,telnetyWWW.
Desde el punto de vista del programador las diferencias entre Programacin de Sistemas y
Programacin de Aplicaciones es que la Programacin de Sistemas requiere
conocimiento sobre el Hardware y el Sistemas Operativo en el que se desarrollar el
programa
. Otra diferencia son las bibliotecas a utilizar. Porotrolado,sedebendeemplearlas
mismasbuenasprcticasdeprogramacin.
La mayora del cdigo para Linux y Unix se escribe a nivel sistema. Ya que las llamadas al
sistemasondependientesdelhardware,muchodeestecdigoseescribeenlenguajeC.
Las
llamadas al sistema
son funciones que se invocan desde nivel usuario hacia el kernel
pararequerirunservicioorecursodelsistemaoperativo.
Ejemplosdellamadasalsistemason:
SistemadeArchivo:
open()
,
read()
,
write()
,
close()
,etc.
Procesos
fork()
,
getpid()
,
set_thread_area()
,etc.
Red:
socket()
,
bind()
,etc.
Cada Sistema Operativo define diversas llamadas al sistema. Por ejemplo en el caso de
sistemas operativos Windows, se definen miles de llamadas al sistema. En el casodeLinuxel
nmerodellamadasalsistemasonaproximadamenteunas300.
NOTA
:LaltimaafirmacincorrespondealaeradelafamiliaWindows9x.Actualmente,sepuedeveruna
listarecopiladapormetasploitdellamadasdesistemasdewindows
enestaliga
.
Algunasllamadasasistema
La documentacin completa de estas llamadas a est en losmanualesdelprogramador(man
pages). En ubuntu estaspginasn pueden no haber sido instaladas automticamente, se
debeninstalarlospaquetesmandbymanpagesdev
Laboratoriode
SistemasOperativos
Abrirarchivos:
Antes que los datos de un archivo se puedan leer,
ste debe de ser abierto utilizando las
llamadasasistema
open()
o
create()
.
intopen(constchar*name,intflags)
intopen(constchar*name,intflags,mode_tmode)
Sisepuedeabrirexitosamente,regresaun
descriptordearchivo.
Comienzaenlaposicin0delarchivo,y
Elarchivoseabredeacuerdoalcontenidodelparmetroflags.
La variable
flags puede contener diferentes valores dependiendo de la operacin que
deseamosrealizarsobreelarchivo:
O_RDONLY
,
O_WRONLY,
or
O_RDWR
.
La variable
modo puede tomar los siguientes valores:
O_APPEND,
O_CREAT,
O_EXCL
O_TRUNC
.Lainformacindetalladaseencuentraen
manopen
.
La definicin de estas funciones, as como las constantes utilizadas en los flags, se pueden
encontrarenlossiguientesencabezados.
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
Lecturamedianteread()
Elmecanismomsbsicoycomnmenteusadoparaleer,eslallamadaasistema
read()
,se
define:
#include<unistd.h>
ssize_tread(intfd,void*buf,size_tlen)
Cada llamadaleehastaunacantidadde
len bytes apartirdelaposicinactualreferenciadapor
el descriptor de archivo
fd,
y los guarda en
buf. Regresa el nmero de bytes escritosen
buf
,o
1siocurreunerror.
Escribiendoconwrite()
Lallamadaasistemamsbsicaycomnes
write()
.Sedefine:
#include<unistd.h>
ssize_twrite(intfd,constvoid*buf,size_tcount)
La llamada a
write() escribe una cantidad de
count bytes a partir de la posicin actual
referenciadapor
fd
.Regresaelnmerodebytesescritos,o1encasodeerror.
Cerrararchivos
Cuando un programa ha terminado de trabajar con un file descriptor, debe desasociar el file
descriptordelarchivomediantelallamadaasistema
close()
:
#include<unistd.h>
intclose(intfd)
Regresaun0encasodexito,oun1encasodeerror.
Laboratoriode
SistemasOperativos
Unejemplodellamadasalsistema
Esteejemploesunacodificacinsimpledelcomando
cp
:
/* PROGRAMA: copiar.c
FORMA DE USO:
./copiar origen destino
VALOR DE RETORNO:
0: si se ejecuta satisfactoriamente.
-1: si se da alguna condicion de error
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
/* open() */
/* open() */
/* open() */
/* read() y write() */
Laboratoriode
SistemasOperativos
close(fd_origen);
close(fd_destino);
}
user@localhost~$./copiacopiar.ccopiar2.c
user@localhost~$echo$?
0
user@localhost~$./copiacopiar3.ccopiar2.c
copiar3.c:Nosuchfileordirectory
user@localhost~$echo$?
255
FileI/O:writeback,SynchronizedI/O
Comportamientodelwrite(writeback)
La disparidad en el rendimiento entre procesadores y discos duros hara que para efectos de
rendimiento se retrase laescritura.Cuandounaaplicacinenelespacio delusuariorealizauna
llamada al sistema
write(), el kernel de Linux realiza un par de revisiones, y entonces
simplemente copia los datos en un buffer interno al sistema operativo. Despus, en segundo
plano, elkerneltomatodoslos bufferssuciosdetodoslos usuarios(esdecir,que nohansido
an escritos a disco), los ordena ptimamente (de tal forma que la cabeza escritora del disco
duro minimice su trayectoria), y los escribe en el disco.
Este proceso se conoce como
writeback. Esto permite al kernel aplazar las escrituras a periodos ms desocupados y
procesarenlotemuchasescriturasjuntas.
Un problema final con las escrituras retrasadas tiene que ver con el reporte de ciertos
errores de I/O. Cualquier error de I/O que ocurra durante la escritura a disco por
ejemplo, una falla fsica de disco no puede ser reportada al proceso que emiti la
Laboratoriode
SistemasOperativos
peticindeescritura.
El kernel trata de minimizar los riesgos de estas escrituras diferidas. Para asegurar que los
datos son escritos oportunamente, el kernel establece una edadmximadelbuffer,y escribea
disco todos los buffers sucios antes de que maduren ms all del tiempo dado.Losusuarios
pueden configurar este valor en el archivo /proc/sys/vm/dirty_expire_centisecs. El valor est
especificadoencentsimasdesegundo.
SynchronizedI/O
Aunque la sincronizacin de I/O es un tema importante, los problemas asociados con las
escrituras retrasadas no deben ser temidos. Las escrituras mediante buffers proporcionan una
mejora enorme en el rendimiento, y consecuentemente, cualquier sistema operativo que
merezca la etiqueta de moderno, implementa escrituras diferidas mediante buffers. Sin
embargo, hay ocasiones en las que las aplicaciones desean controlar de manera precisa el
momento en que los datos llegan al disco. Para esos usos, el kernel de Linux proporciona un
puado de opciones que permiten negociar el rendimiento por medio de las operaciones
sincronizadas.
fsync() asegura que todos los datos sucios asociados con el archivo mapeado por el file
descriptor
fd sean escritos al disco en el momento en que se ejecuta esa llamada. Menos
ptimo, pero de ms amplio alcance, la llamada a sistema
sync() se proporciona para
sincronizartodoslosbuffersaldisco.
if((fd_destino=open(argv[2],O_WRONLY|O_TRUNC|O_CREAT,0666))==1)
podramosincluirlabandera
O_SYNC
delasiguienteforma:
if
(
(fd_destino=open(argv[2],O_WRONLY|O_TRUNC|O_CREAT|
O_SYNC
,0666))==
1)
Lecturaspredictivas
"Readahead"serefierealaaccindeleermsdatosdeldiscoydelapginadecachenla
quesehizolapeticindelectura,enefecto,leyendounpocohaciaadelante.
I/Ousandobuffers(lenguajeCestndar)
El rendimiento de I/O es ptimo cuando las peticiones se realizan entre lmites alineados por
bloques y de tamao mltiplo entero del tamao de bloque. En la prctica, los tamaos de
bloque normalmente son 512, 1,024, 2,048,4,096.Enconsecuencia,laeleccinmssencilla
es haceroperacionesdeI/Ousandobuffersgrandesqueseanmltiplosdelostamaostpicos,
porejemplo4,096o8,192bytes.
El problema, por supuesto, es que los programas rara vez efectan estas operaciones en
trminos de bloques. Los programas trabajan con campos, lneas o caracteres, no con
abstracciones como los bloques. Para remediar esta situacin, los programas pueden utilizar
Laboratoriode
SistemasOperativos
las funciones de usuario para I/O con buffers de usuario, declarados por el programador. La
biblioteca estndar de C provee la librera estndar deI/O(comnmentellamada
stdio
),lacual
a su vez provee una solucin de utilizacin debuffersparausuarios,deformaindependientea
la arquitectura sobre la que corra el sistema. Estas rutinas de lectura y escritura utilizando
buffers de usuarios pueden utilizarse incluso no solo para escribir a disco, sino para escribir a
cualquier dispositivo futuro o incluso para escribir a sockets de red y as enviar writes y
readsprovenientesdeotrosprogramas,posiblementeresidentesenotrasmquinasdelared.
Apuntadoraarchivo
Es un apuntador al tipo de dato FILE, definido en <stdio.h>, que representa el apuntador a
archivo. Hablando del estndar I/O , un archivo abierto es llamado "stream". Estos Streams
puedenabrirseparaescritura,lecturaoambos.
Paraabrirunarchivoseutilizaellafuncin
fopen()
yparacerrarlo
fclose().
LeyendoStreams
LabibliotecaestndardeCimplementadiferentesfuncionesparaleerdeunstreamabierto.
Leyendouncaracteralavez.
Lafuncin
fgetc()
seusaparaleerunslocaracterdelstream.
Leerunalneacompleta.
Lafuncin
fgets()
leeunacadenadecaracteres(string)delstream.
Leerdatosbinarios.
Para algunas aplicaciones, leer caracteres individuales o lneas no es suficiente. Algunas
veces, los desarrolladores quieren leer y escribir datos binarios complejos, por ejemplo
estructuras.Paraesto,labibliotecaestndarI/Oprovee
fread().
Paramayorreferenciasobreestasfunciones,consultarlosmanualesdecadafuncin.
Escribiendoaunstream
LabibliotecaestndardeCimplementavariasfuncionesparaescribirenun
streamabierto.
Escribiendouncarcteralavez
.
Lacontrapartedefgetc()esfputc():
Escribiendounacadenadecaracteres.
Lafuncin
fputs()
esusadaparaescribirunacadenaaunstreamdado
.
Laboratoriode
SistemasOperativos
E
scribiendounacadenadecaracteres.
L
afuncin
fputs()
esusadaparaescribirunacadenadecaracteresaunstreamdado.
EjemplodeunprogramaqueusaI/Oenbuffers.
Comoejemplo,sevaareescribirlafuncincopiar.cusandobuffersdeI/O.
/* PROGRAMA: fcopiar.c
FORMA DE USO:
fcopiar origen destino
VALOR DE RETORNO:
0: si se ejecuta satisfactoriamente.
-1: si se da alguna condicion de error
*/
#include <stdio.h>
#include <stdlib.h>
Laboratoriode
SistemasOperativos
MapeoaMemoria(Memorymap)
Los archivos mapeados a memoria son una copia idntica enmemoriadeunarchivoendisco.
La imagen corresponde byte por byte con el archivo en disco. Los archivos mapeados a
memoriatienendosprincipalesventajas:
LasoperacionesdeI/Osobrearchivosmapeadosamemoriaevitanlosbuffersdelkernel,
por lotantolastransferenciasI/O sonmuchomsrpidas.Nota:yaqueelkerneltieneun
overhead,estatasadetransferenciaesmsnotoriaconarchivosgrandes.
Aparte de los posibles fallos de pgina, leer de y escribir en un archivo mapeado a
memoria no incurre en ninguna llamada a sistema osobrecargaporcambiodecontexto.
Estansimplecomoaccesarmemoria.
Los datos del archivo mapeado pueden ser accedidos internamente mediante
apuntadores en lugar de las funciones comunes para la manipulacin de archivos.
Adems, buscar en el mapeo involucra manipulaciones triviales de apuntadores. Nohay
necesidaddelallamadaasistemalseek().
Porestasrazones,mmap()esunaopcininteligenteparamuchasaplicaciones.
Hayunpardepuntosamantenerenmentecuandoseusammap():
Los mapeos a memoria tienen siempre un tamao que es mltiplo entero de pginas.
As, la diferencia entre el tamao del archivo y el nmero entero de pginas es
desperdiciado como espacio sobrado. Para archivos pequeos, un porcentaje
significativo del mapeo podra ser desperdiciado. Por ejemplo: con pginas de 4KB, un
archivode7bytesmapeadodesperdicia4,089bytes.
Los mapeos a memoria debe ajustarse dentro del espacio de direcciones del proceso.
Con un espacio de direcciones de 32 bits, un nmero muy grande de mapeos de
diferentes tamaos podra resultar en la fragmentacin del espacio de direcciones,
Laboratoriode
SistemasOperativos
haciendo difcil encontrar grandes regiones libres contiguas. Este problema, por
supuesto,esmuchomenosaparenteconespaciosdedireccionesde64bits.
Hay un overhead al crear y mantener los mapeos a memoria y las estructuras dedatos
asociadas dentro del kernel. Este overhead es obviado generalmente por la eliminacin
de la doble copia mencionada en la siguiente seccin, particularmente para archivos
grandesyfrecuentementeaccedidos.
Acontinuacinsereescribeelprogramacopiarutilizandolasfunciones
mmap()
y
unmap()
.
/* PROGRAMA:
copiar_mm.c(utilizando mapeo de memoria)
FORMA DE USO:
./copiar_mm origen destino
VALOR DE RETORNO:
0: si se ejecuta satisfactoriamente.
-1: si se da alguna condicion de error
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <
sys/mman.h
>
int main(int argc, char *argv[])
{
int fd_origen;
int fd_destino;
int nbytes;
void *src;
struct stat statbuf;
/*Analisis de los argumentos de la linea de comandos*/
if (argc != 3) {
fprintf(stderr,"Forma de uso: %s origen destino\n", argv[0]);
exit(-1);
}
/*Apertura del archivo en modo solo lectura*/
if ((fd_origen=open(argv[1],O_RDONLY))== -1) {
perror(argv[1]);
exit(-1);
}
/* Apertura o creacion de archivos en modo solo escritura*/
Laboratoriode
SistemasOperativos
user@localhost~$time./copiar_mm./100wrds./wrds
corrida
1
2
3
4
5
6
7
8
9
10
Promedio
fcopiar
27.27
26.93
27.25
27.06
27.15
26.82
26.88
27.29
27.83
27.29
27.177
copiar_mm copiar_fw
1.46
27.09
1.18
25.21
1.64
25.13
0.79
26.34
1.1 25.09
0.81
25.34
1.25
25.09
1.21
25.67
1.02
25.18
1.26
25.64
1.172
25.578
copiar
1.03
1.39
1.37
1.86
1.54
0.95
0.65
cp
1.23
1.34
1.27
1.25
1.45
1.29
1.26
1 1.21
1.31
0.99
1.32
1.51
1.242
1.28
Tabla1.Comparacinentrelostiemposdeejecucindelasvariantesdelprogramacopiar.c
CrticasalaBibliotecaI/OEstndar.
Tan ampliamente usado como es el I/O Estndar, algunos expertos apuntan a fallas en l.
Laboratoriode
SistemasOperativos
Una implementacin alternativa podra evitar la doble copia al hacer que cada peticin de
lectura regrese un apuntador al buffer I/O estndar. Los datos podran entonces ser ledos
directamente, dentro del buffer I/O estndar, sin la necesidad de una copia extraa. En el
evento de que la aplicacin quisiera que los datos se almacenarn en su propio buffer
localquizs escribira lpodrasiemprerealizarlacopiamanualmente.Estaimplementacin
proveera una interfaz libre, permitiendo a las aplicaciones indicar cuando se apropian de un
pedazo del buffer de lectura. Las escrituras seran un poco ms complicadas, pero an se
evitara la doble copia. Cuando se emite una peticin de escritura, la implementacin
almacenara el puntero. Al final, cuando se est listo para vaciar los datos al kernel, la
implementacin podra recorrer su lista de apuntadores almacenados, escribiendo a disco los
datos. Esto podra ser hecho usando I/O de dispersinreunin,va
writev()
,yporlotantosolo
una llamada a sistema. Existen bibliotecas userbuffering altamente ptimas, que resuelven el
problema de la doble copia con implementaciones similares a las que se han discutido.
Alternativamente, algunos desarrolladores eligen implementar sus propias soluciones. Pero a
pesardeestasalternativas,I/Oestndarpermanecepopular.
Implicacionesdel
buffering
delEstndarI/O:
Mejoresquelasllamadasasistemaparapeticionespequeasodesalineadasdebido
albufferingdeflujo.
Cuandoseleencaracteresusebibliotecasestndar.
Cuandoseleanbloquesusellamadasasistema(porladoblecopia).
Elanchodebandaeslimitadoalcopiardatosalbufferdeflujo.
Parapeticionesgrandes,
fwrite
evitaelbuffer.
fread
noevitaelbuffer.
====Laboratorio====
Actividadesarealizarenestaprcticaseencuentrandescritaseneste
documento,susrespuestasdebenregistrarseen:
E
nlacealformulario:
Prctica7:ProgramacindeSistemas(SystemProgramming)
.
Retroalimentacin:
RetroalimentacinProgramacindeSistemasylaboratorio
Laboratoriode
SistemasOperativos
./fusionar<archivo1><archivo2><salida>
Sin embargo, por tragedias que involucran un CPU abierto durante el mantenimiento y malas
prcticas de dnde colocar un refrescodecola,eldiscoduroque contenael cdigosedaoy
solo se consigui recuperar fragmentos del cdigo fuente orginal. Es su deber reescribir el
cdigo partiendo de lo que se recuper y que se despliega en la tabla de mas abajo. Como
buen desarrollador
, entregar un archivo de parche diferencial con loscambiosenlaslineas,
es decir, utilizar la herramienta
diff
. Paraindicarcualessonlaslneasrestauradasysunuevo
valor.
#include <stdio.h>
#include <stdlib.h>
#include <sys/____.h>
#include <sys/____.h>
#include <____.h>
#include <____.h>
/
* open() */
/
* open() */
/
* open() */
/
* read() y write() , close() */
Laboratoriode
SistemasOperativos
close(____);
}
Puedesverunejemplodelaejecucindeesteprograma:
user@localhost~$
ls
body.c
fusionar.c
fusionar
headers.c
user@localhost~$
catheaders.c
#include<stdio.h>
user@localhost~$
catbody.c
constchar*msg="HelloEarthlings!"
intmain()
{
printf("MessagefromMars:%s\n",msg)
return0
}
user@localhost~$
./fusionarheaders.cbody.csecretProgram.c
user@localhost~$
ls
body.c
fusionar.c
fusionar
headers.c
secretProgram.c
user@localhost~$
gccWallosecretProgramsecretProgram.c
user@localhost~$
./secretProgram
MessagefromMars:HelloEarthlings!
Adems de este cdigo original se pretende recuperar archivos que se perdieron de forma
permanenteloscualestienenlassiguientescaractersticas:
*Reportaloscambiosrealizadosencadacdigoutilizandolaherramientadiff:
diffNaurfusionar_orig.cfusionar.c
Referencias
[1]Love,Robert.
LinuxSystemProgramming
,O'REILLY,2007.Biblioteca:QA76.76.O63L692007
[2]Marquez,Fernando.
ProgramacinAvanzadaenUNIX
,3a.edicion,2004.BibliotecaQA,76.76,
.O63,M37,2006(Reserva)
Laboratoriode
SistemasOperativos
Fuentesadicionales