Está en la página 1de 8

Examen de Laboratorio de Sistemas Operativos. Primera Convocatoria 2003/04.

Tercero Ingeniera Informtica


Nombre: Apellidos: Grupo: 24 de Junio de 2004

[Cuestin 1.] Un programador est desarrollando una biblioteca para trabajar con los mecanismos de IPC de System V (semforos, mensajes y memoria compartida). Todos estos mecanismos se basan en una clave que identifica de forma unvoca al recurso con el que se quiere trabajar. Para generar estas claves nicas, el sistema operativo proporciona una llamada (ftok), que toma como argumentos un archivo (que debe existir en el sistema de archivos y debe ser accesible para el proceso que hace la llamada a ftok) y un nmero que identifica al proyecto. Como decisin de diseo para la biblioteca de IPC, el programador ha decidido que va a situar todos los archivos para generar las claves en un directorio dado por una variable la variable de entorno DIRIPC, que estar situado en el directorio temporal (/tmp). Tambin, ha decidido utilizar la siguiente nomenclatura para dar nombre a los archivos: semaph.uid.nombre_semaforo Esto indicar que es un archivo que se ha utilizado para generar una clave de acceso a un semforo, uid ser un entero largo que hace referencia al usuario que ha creado el semforo, y nombre_semaforo ser una cadena que hace referencia al semforo que utiliza esa clave. mailbox.uid.nombre_mailbox Esto indicar que es un archivo que se ha utilizado para generar una clave de acceso a una cola de mensajes, uid ser un entero largo que hace referencia al usuario que ha creado la cola, y nombre_mailbox ser una cadena que hace referencia al semforo que utiliza esa clave. shmem.uid.nombre_memcmp Esto indicar que es un archivo que se ha utilizado para generar una clave de acceso a una zona de memoria compartida, uid ser un entero largo que hace referencia al usuario que ha creado la zona de memoria compartida, y nombre_memcmp ser una cadena que hace referencia a la zona de memoria compartida que utiliza esa clave. La Figura 1 muestra un extracto del aspecto del contenido del directorio que contiene los archivos base para generar las claves. -rwx------rw-------rw------1 garciabe 1 reinaqu 1 reinaqu alumnos prof prof 0 Jun 21 12:51 mailbox.6236.mibuzon 0 Jun 21 18:24 semaph.4961.disponible 0 Jun 21 18:24 semaph.4961.excmut

Figura 1. Extracto del contenido del directorio con las archivos para generar las claves de IPC. Escriba los siguientes comandos para ayudar al programador en su tarea de depuracin de la biblioteca mientras la est desarrollando. Apartado a.- Escriba el comando para crear el directorio donde se van a situar todos los archivos que se creen como base para generar las claves. Ntese que este directorio vendr indicado en la variable de entorno DIRIPC, que dar la ruta relativa al directorio /tmp. mkdir /tmp/$DIRIPC

Apartado b.- Cree un archivo llamado semaphs.txt que contenga un listado en formato largo de todos los archivos creados por el usuario que est ejecutando el comando y utilizados para generar claves de semforos. ls l /tmp/$DIRIPC | grep $USER | grep semaph > semaphs.txt

Apartado c.- Suponiendo que usted es el root, elimine el directorio en el que se almacenan los archivos que se utilizan como base para generar las claves. rm r /tmp/$DIRIPC

Puntuacin: 1 pto.

Tiempo estimado: 10 min. 1

[Cuestin 2.] Se desea implementar un servidor de archivos concurrente (fileserv) que trabaje en modo conectado (SOCK_STREAM) y que pueda funcionar a travs de internet (AF_INET). Para implementar el servidor, se han decidido crear las siguientes funciones: int Serv_Crea_Socket (void); Reserva una posicin en la tabla de descriptores de archivos para almacenar informacin sobre un socket. Devuelve el descriptor del socket creado, si no hay ningn tipo de problema, y -1 en caso de error. int Serv_Reserva_Puerto(int sock, int puerto, struct hostent *hp); Une el socket dado por sock con el nmero de puerto TCP/IP y la direccin dada en la estructura struct hostent. Devuelve -1 si hay algn error, y 0 en caso contrario. int Serv_Asigna_ColaEsc(int sock); Asigna el tamao de la cola de espera a la constante TAM_COLA, y convierte el socket en pasivo. Si existe algn problema al realizar la operacin, devuelve -1. En caso contrario devuelve 0. int Serv_Acepta_Conexion(int sock); Toma como argumento un socket pasivo, y devuelve un socket conectado. Si hay algn error, devuelve -1. En caso contrario, devuelve el descriptor del socket conectado. int Serv_Procesa_Conexion(int sock, char directorio[]); Toma como argumento un socket conectado y la ruta absoluta del directorio que contendr los archivos que sirve el servidor de archivos El servidor se deber invocar de la siguiente forma: fileserv <puerto> <directorio>

donde <puerto> es el nmero de puerto TCP/IP por el que el servidor atender las peticiones recibidas por parte de los clientes, y <directorio> ser la ruta absoluta de un directorio, que deber existir en el sistema, y en el que se situarn los archivos y/o directorios que servir nuestro programa. Apartado a.- Escriba el cdigo de la funcin Serv_Reserva_Puerto.

int Serv_Reserva_Puerto (int sock, int puerto, struct hostent *hp) { struct sockaddr_in si ; memset (&si, 0, sizeof (struct sockaddr_in)); si.sin_family = AF_INET; si.sin_port = htons(puerto); memmove(&si.sin_addr, hp->h_addr, hp->h_length); res = bind(sock, (struct sockaddr *) &si, sizeof(si)); if (res != -1) return sock; else return res; }

Puntuacin: 0,75 ptos.

Tiempo estimado: 10 min.

Apartado b.- Escriba el cdigo del programa principal para crear el servidor de archivos concurrente. El servidor deber capturar la combinacin de teclas Ctrl+C (seal SIGINT) para terminar correctamente el programa, lo que implica que no se deben dejar procesos hurfanos, ni sockets abiertos.

int manejadorSIGINT (int); int main (int argc, char *argv[]) { int puerto; int se, sc; char maquina[LON_MAQUINA]; struct hostent *hp; if (signal (SIGINT, manejadorSIGINT) == SIG_ERR){

Examen de Laboratorio de Sistemas Operativos. Primera Convocatoria 2003/04. Tercero Ingeniera Informtica
Nombre: Apellidos: Grupo: 24 de Junio de 2004
fprintf (stderr, Error asignando manejador Ctrl-C\n); exit(1); } se = Serv_Crea_Socket (); if (se == -1) { fprintf(stderr, Error creando socket\n); exit(2); } /* Obteniendo datos del servidor */ gethostname(maquina, sizeof(maquina)); hp = gethostbyname (maquina); sscanf (argv[1], %d, &puerto); if (Serv_Reserva_Puerto(se, puerto, hp) == -1){ fprintf (stderr, Error asignando puerto\n); exit(3); } if (Serv_Asigna_ColaEsc(se) == -1) { fprintf (stderr, Error poniendo el socket a la escucha\n); exit(4); } for (;;){ sc = Serv_Acepta_Conexion (se); childpid = fork(); if (childpid == 0) { /* Hijo */ if (signal (SIGINT, SIG_IGN) == SIG_ERR) { fprintf(stderr, Error ignorando seal\n); exit(2); } close (se); Serv_Procesa_Conexion (sc, argv[2]); close (sc); exit(0); } else if (childpid > 0){ /* Padre */ close (sc); } else { /* Error */ fprintf (stderr, Error creando proceso hijo\n); close (sc); close (se); exit(0); } } close (se); } void manejadorSIGINT(int signal){ pid_t waitpid; int status; close (sc); close (se); waitpid = wait (&status); while (waitpid >0 || (waitpid == -1 && errno == EINTR)) waitpid = wait (&status); exit(0); }

Puntuacin: 2 ptos.

Tiempo estimado: 30 min. 3

Apartado c.- Escriba el cdigo de una funcin C llamada enviar_archivo que pueda ser llamada por la funcin serv_procesa_conexion, y que se encargue de enviar al cliente a travs del socket la siguiente informacin: Si el archivo solicitado no existe, al cliente se le enviar el siguiente mensaje: ERR-01: Archivo inexistente\r\n. Ntese que se utiliza como terminador de mensaje el conjunto de caracteres \r\n. Si el archivo solicitado existe, pero no se tiene permiso de lectura sobre el mismo, se debe enviar el mensaje: "ERR-02: Sin permiso\r\n". Por ltimo, si el archivo existe y se tiene permiso de lectura, se deber enviar una cabecera con el tamao en bytes del archivo (Por ejemplo, Size: 456 bytes\r\n, y a continuacin se deben enviar, carcter a carcter, los 456 bytes de que consta el archivo. El prototipo de la funcin que debe implementar es el siguiente: void enviar_archivo (int sc, char directorio[], char archivo[]) donde: sc es el descriptor del socket conectado al cliente. directorio contiene la ruta absoluta del directorio donde estn los archivos que sirve el servidor, y archivo es el nombre del archivo solicitado por el cliente. NOTA: El archivo se debe tratar a bajo nivel.

void enviar_fichero (int sc, char directorio[], char fichero[]) { /* Escriba aqu el cdigo necesario */ struct stat status; int fd; FILE *fs; char ch; char abs_path[LON_PATH]; sprintf (abs_path, %s/%s, directorio, fichero); fs = fdopen (sc, "r+b"); if (stat(abs_path, &status) != 0) { fprintf (fs, "ERR-01: Archivo inexistente\r\n"); fflush (fs); fclose (fs); return; } if ( (status.st_mode & S_IREAD) != S_IREAD) fprintf (fs, "ERR-02: Sin permiso\r\n"); fflush (fs); fclose(fs); return; }

/* Impresin de la cabecera */ fprintf (fs, "Size: %d bytes\r\n", status.st_size); fflush (fs); fd= open (abs_path, O_RDONLY); if ( fd>0 ) { leidos = read (fd, &ch, sizeof(char)); while (leidos >0) { fputc(ch, fs); leidos = read (fd, &ch, sizeof(char)); }

Examen de Laboratorio de Sistemas Operativos. Primera Convocatoria 2003/04. Tercero Ingeniera Informtica
Nombre: Apellidos:
close(fd); } fflush (fs); fclose (fs); }

Grupo: 24 de Junio de 2004

Puntuacin: 1,25 ptos.

Tiempo estimado: 20 min.

[Cuestin 3.] Queremos sincronizar 2 tipos de procesos. Tenemos un conjunto de procesos generadores que se dedican a crear mensajes de dos tipos (mensajeA, mensajeB) y los envan a 2 colas de mensajes (ColaA, ColaB). Las posiciones de ambos mensajes en sus respectivas colas debe ser la misma. Adems dichas colas de mensajes slo pueden albergar MAX mensajes (cada una de ellas). Cuando hay al menos un mensaje en ambas colas, interviene un proceso transformador que recoge un mensaje de cada una de ellas, realiza una operacin sobre ambos y muestra el resultado por la salida estndar. Haciendo uso de la biblioteca de colas de mensajes realizada en el laboratorio, escriba el cdigo C del proceso Transformador y los procesos Generadores. Omita la inclusin de ficheros de cabecera. Explique el nmero de colas de mensajes necesarios para resolver el problema y d una breve explicacin del uso de cada una de las colas. Disponemos de las siguientes funciones: void genera_mensaje(Message *msj,char tipo); Recibe como argumentos un mensaje (que se pasar por referencia) y un carcter que indica si el mensaje es de tipo A o B. Servir para crear e inicializar el mensaje. int MailBox_Exist(char nombre_buzon[ ]); Esta funcin ampla la biblioteca de colas de mensajes realizada en el laboratorio. Recibe el nombre de una cola de mensajes y devuelve 1 en caso de que exista esa cola y 0 en caso contrario.

Explicacin: Este problema se puede ver como una variacin del esquema Productor-Consumidor visto en la asignatura de teora, e implementado en las clases de laboratorio. Para resolverlo necesitamos cuatro colas de mensajes: ColaA: Es la cola donde se van a almacenar los mensajes de tipo A. ColaB: Es la cola donde se van a almacenar los mensajes de tipo B. Contador: Va a servir para controlar el tamao mximo (MAX) de ambas colas, puesto que las colas se gestionan en paralelo. ExcMut: Cola para proteger la seccin crtica en los generadores, de forma que no se pueda interferir el envo de los mensajes a las colas A y B por otro generador. (Tenga en cuenta que las posiciones de los mensajes que enva un generador a las colas A y B debe ser la misma en ambas colas).

Iniciador: int i; Message token; Create_Message("token",&token); ColaA=MailBox_Create("ColaA"); ColaB=MailBox_Create("ColaB"); /* Inicializacin del contador */ if(!MailBox_Exist("Contador")){

Contador=MailBox_Create("Contador"); for(i=0;i<MAXIMO;I++) MailBox_Send(Contador,token); } else Contador=MailBox_Create("Contador"); /* Inicializacin de la exclusin mutua */ if(!MailBox_Exist("ExcMut")){ ExcMut=MailBox_Create("ExcMut"); MailBox_Send(ExcMut,token); } else ExcMut=MailBox_Create("ExcMut");

Generador: extern MailBox Contador,ExcMut,ColaA,ColaB; Message token,msjA,msjB; iniciador(); for(;;){ genera_mensaje(&msjA,'A'); genera_mensaje(&msjB,'B'); MailBox_Receive(Contador,&token); MailBox_Receive(ExcMut,&token);//Operacion Down si fuese un semaforo MailBox_Send(ColaA,msjA); MailBox_Send(ColaB,msjB); MailBox_Send(ExcMut,token); } Transformador: extern MailBox Contador,ColaA,ColaB; Message token,msjA,msjB; iniciador(); Message_Create("token",&token); for(;;){ MailBox_Receive(ColaA,&msjA); MailBox_Receive(ColaB,&msjB); Transformar (msjA, msjB); MailBox_Send(Contador,token); } }

Puntuacin: 2 ptos.

Tiempo estimado: 30 min.

[Cuestin 4.] Escriba el cdigo de un programa C, ejelista, que reciba como argumento el nombre de archivo que contendr un comando por lnea. El programa ejelista deber ejecutar, uno tras otro, todos los comandos del archivo que se le pasa como argumento de forma que hasta que no termine la ejecucin de uno, no puede empezar a ejecutarse el siguiente. ejelista se deber invocar de la siguiente forma: ejelista <archivo-comandos> ps fu i6373 ls -la who Figura 2. Archivo de comandos

Un ejemplo de archivo de comandos se muestra en la Figura 2. Para facilitar el ejercicio, disponemos de la siguiente funcin:

Examen de Laboratorio de Sistemas Operativos. Primera Convocatoria 2003/04. Tercero Ingeniera Informtica
Nombre: Apellidos: Grupo: 24 de Junio de 2004

int makeargv(char *linea, char ***vector); Dado una cadena linea, que contiene tokens separados por espacios en blanco, divide esa lnea y crea un array de cadenas de caracteres (con el mismo formato que argv) que contendr en cada una de sus posiciones los tokens de la lnea. Por ejemplo, una llamada a esta funcin, tendra la forma: numTokens=makeargv(ps fu juan,&vector); En este caso, el array vector contendra lo siguiente: vector[0]=ps, vector[1]= -fu y vector[2]= i6373 NOTAS: -

No se puede usar la llamada al sistema system ( ). No se pueden quedar procesos hurfanos.

void recorre(char *); void ejecuta (int, char **); int main(int argc,char*argv[]){ struct stat statbuf; if(argc!=2){ fprintf(stderr,"Uso: %s <nombre_archivo>\n",argv[0]); exit(-1); } if(stat(argv[1],&statbuf)==-1){ fprintf(stderr,"Archivo no existe\n"); exit(-1); } recorre(argv[1]); return 0; } void recorre(char archivo[]) { FILE *fp; char linea[MAX]; fp = fopen(archivo, "r"); if (fp == NULL){ fprintf(stderr,"Error abriendo archivo\n"); exit(2); } fgets(linea, sizeof(linea), fp); while (!feof(fp)){ ejecuta (linea); fgets(linea, sizeof(linea), fp); } fclose(fp); } void ejecuta (char *linea) {

char **miargv; pid_t childpid; int status; int waitreturn; int args;

childpid=fork(); if(childpid<0){ fprintf(stderr,"Error en el fork\n"); exit(-1); } else if(childpid==0){ // Hijo if ((args=makeargv(linea, &miargv)) <0){ fprintf(stderr,"error creando args\n"); exit(1); } if (execvp(miargv[0], miargv)<0){ perror("Error en execvp...\n"); exit(0); } } else{ // Padre waitreturn=waitpid(childpid, &status, 0); } }

Puntuacin: 2 ptos.

Tiempo estimado: 30 min.

[Cuestin 5.] Se desea aumentar la biblioteca creada en el laboratorio para semforos en UNIX System V con una funcin. Para implementarla, utilizaremos nicamente las llamadas al sistema que nos proporciona el sistema operativo. En concreto: int Semaph_Down_Condition(Semaph); Esta funcin realiza una operacin down condicional sobre un semforo. Recibe como argumento el semforo sobre el que queremos actuar, si el valor del mismo es mayor o igual a 1, realizaremos una operacin down decrementando en una unidad su valor y el valor de retorno ser 1. En caso contrario, si el valor del semforo es 0, devolveremos 0 y no ejecutaremos la operacin down. Si hay algn tipo de error, devolveremos -1.

int Semaph_Down_Condition(Semaph sem) { struct sembuf op_down_0 = {0, -1, 0}; int resultCtl,resultOp; resultCtl = semctl((int)sem, 0, GETVAL,0); if(resultCtl==-1) return (-1); if(resultCtl>=1){ resultOp = semop((int)sem, &op_down_0, 1); if(resultOp!=-1) return(1); else return(-1) } else /*resultCtl==0*/ return(0); }

Puntuacin: 1 pto.

Tiempo estimado: 10 min.

También podría gustarte