Los ejemplos de programación mediante hilos (y sus correspondiente versiones de procesos) que se presentan como ejemplos demostrativos, emplean numerosas funciones comunes, que están agrupadas en archivos cuyo código fuente se puede encontrar en el directorio source del paquete de ejemplos, mientras que los ficheros de cabecera de dichas funciones se encuentran en el directorio include.
El objetivo de la creación de esta biblioteca de funciones es hacer que los ejemplos se reduzcan a incluir el código mínimo encargado de la resolución concreta del problema. Además, en todos los ejemplos se plantearon necesidades comunes, como la obtención de estadísticas de tiempos de ejecución, la inicialización, obtención de argumentos, etc. En concreto esta biblioteca de rutinas contiene una serie de funciones que se encarga de simular los mútex y variables de condición para todas las versiones de procesos de los distintos ejemplos planteados basándose para ello en semáforos.
A continuación se presenta el listado de los
distintos archivos que componen la biblioteca de funciones
comunes :
PARAM.H : Definición del estilo de las declaraciones y definiciones de funciones.
#ifndef PARAM_H #define PARAM_H #if defined(__STDC__) | defined(ANSI_C) | defined(MSC) | defined(M_XENIX) #define Param(x) x #else #define Param(x) () #endif /* ANSI or PCC style decls */ #endif
ERROR.H : Declaración de las funciones de mensajes de error.
#ifndef ERROR_H #define ERROR_H #include <errno.h> #include "param.h" void ErrorFatal Param((char *mensaje)); void Error Param((char *mensaje)); #endif
INCLUDE.H : Agrupación de cabeceras a incluir para el ejemplo del servidor.
#ifndef INCLUDE_H #define INCLUDE_H #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netdb.h> #include <errno.h> #include <signal.h> #include <fcntl.h> #include <string.h> #include <sys/ipc.h> #include <sys/msg.h> #include <sys/stat.h> #include <unistd.h> #endif
TIPOS.H : Declaración de constantes para el ejemplo del servidor.
/*********************************************/ /* DEFINICION DE TIPOS Y CONSTANTES GLOBALES */ /*********************************************/ #ifndef TIPOS_H #define TIPOS_H /************************************************/ /* I N C L U S I O N D E L I B R E R I A S */ /************************************************/ #include <sys/types.h> #include <netinet/in.h> #include "param.h" #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #define LONG_TEXTO 40 #define MAX_LONG_TRAMA LONG_TEXTO #define PUERTO_TCP 6501 #define HOST_SERVIDOR "127.0.0.1" /* Definicion del Tipo de Direccion Internet */ typedef struct sockaddr_in TDireccion; #endif /* TIPOS_H */
TCP.H : Declaración de funciones de gestión de sockets TCP.
#ifndef TCP_H #define TCP_H #include <sys/types.h> #include "tipos.h" int CrearSocketTCP Param((u_short puerto, TDireccion *)); int OpenServidor Param((char *hserv, int puerto)); int CloseServidor Param((int Socket)); int EnviarTrama Param((int Socket, char Tipo, char *Datos)); int RecibirTrama Param((int Socket, char *Datos)); #endif
TIEMPO.H : Declaración de funciones de gestión de tiempos.
#ifndef TIEMPO_H #define TIEMPO_H #include <stdio.h> #include <sys/time.h> #include <unistd.h> void DiffTime(struct timeval *t1, struct timeval *t2, struct timeval *d); void AddTime (struct timeval *t1, struct timeval *t2, struct timeval *s); void DivTimeInt (struct timeval *t1, long n, struct timeval *d); void AdjustTime (struct timeval *t); void PrintTime(char *mensaje, struct timeval *t1, struct timeval *t2); #endif /* TIEMPO_H */
GETSTATS.H : Declaración de funciones de gestión de estadísticas.
#ifndef GETSTATS_H #define GETSTATS_H #include <stdio.h> #include <sys/time.h> #include <sys/resource.h> /* Definicion de la estructura de datos estadisticos */ typedef struct s_estad_t { unsigned long t_user; /* Tiempo en modo usuario en miliseg. */ unsigned long t_system; /* Tiempo en modo sistema en miliseg. */ unsigned long t_real; /* Tiempo real transcurrido */ #ifndef WITH_TIMES struct rusage ru; /* Datos sobre utilizacion de recursos */ #endif } estad_t; #ifdef WITH_TIMES void gettimes(unsigned long *user, unsigned long *system, unsigned long *real); void printtimes(FILE *f, unsigned long *user, unsigned long *system, unsigned long *real); void ObtenerTiempo(estad_t *e); void PrintTiempos(FILE *f, estad_t *e0, estad_t *e1); #else /* No WITH_TIMES */ void getstats(struct rusage *ru, unsigned long *user, unsigned long *system, unsigned long *real); void printstats(FILE *f, struct rusage *ru, unsigned long *user, unsigned long *system, unsigned long *real); void getestad(estad_t *e); void printestad(FILE *f, estad_t *e0, estad_t *e1); #endif #endif /* GETSTATS_H */
GETARGS.H : Declaración de funciones de obtención de argumentos y otras.
#ifndef GETARGS_H #define GETARGS_H /* Definicion de constantes */ #define TAM_MATRIZ 1024 /* Tamano maximo del sistema */ #define N_SIST 4 /* No.max.de sistemas a resolver con misma matriz */ /* Definicion de macros de acceso a una Matriz */ #define A(f,c) A[f*n + c] #define x(f,c) x[f*nsist + c] #define b(f,c) b[f*nsist + c] /* Estructura de los datos de los sistemas triangulares Ax = b */ typedef struct s_datos_t { double *A; /* Matriz A de coeficientes Triangular */ double *x; /* Matriz x de incognitas de los sist. */ double *b; /* Matriz b de term.indep. de los sist.*/ } datos_t; /* Obtener la linea de argumentos */ void GetArgs (int argc, char *argv[], int *n, int *nsist); void GetArgs2(int argc, char *argv[], int *n, int *nsist, int *nhilos); /* Inicializacion de los datos de los sistemas: Ax = b */ void init_data(datos_t *dat, int n, int nsist); /* Imprimir la solucion de los sistemas */ void PrintSolucion(datos_t *dat, int n, int nsist); /* Creacion y destruccion de memoria compartida */ datos_t *CrearMemoria(int *shmem_id, int n, int nsist); void DestruirMemoria (int *shmem_id, datos_t *d); #endif /* GETARGS_H */
SEMAFORO.H : Declaración de funciones de gestión de semáforos.
#ifndef SEMAFORO_H #define SEMAFORO_H #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int sem_create (key_t key, int initval); int sem_open (key_t key); void sem_remove (int id); void sem_close (int id); void sem_op (int id, int value); #define sem_wait(idsem) sem_op(idsem, -1) #define sem_signal(idsem) sem_op(idsem, 1) #endif /* SEMAFORO_H */
MUTEX.H : Declaración de funciones de simulación de mútex.
#ifndef MUTEX_H #define MUTEX_H #include "semaforo.h" /* Definicion del tipo Mutex, implementado mediante un Semaforo */ typedef int mutex_t; int mutex_init (mutex_t *mutex, key_t mutex_key); int mutex_destroy (mutex_t *mutex); int mutex_lock (mutex_t *mutex); int mutex_unlock (mutex_t *mutex); #endif /* MUTEX_H */
COND.H : Declaración de funciones de simulación de variables de condición.
#ifndef COND_H #define COND_H #include "semaforo.h" #include "mutex.h" /* Definicion del tipo Variable de Condicion, implementado con semaforos */ typedef struct _cond_t { int delay; /* Semaforo asociado a los procesos en espera de la condicion */ int delay_cont; /* Contador de procesos en espera de la condicion */ } cond_t; int cond_init (cond_t *varcond, key_t cond_key); int cond_destroy (cond_t *varcond); int cond_wait (cond_t *varcond, mutex_t *mutex); int cond_signal (cond_t *varcond); #endif /* COND_H */
ERROR.C : Definición de funciones de mensajes de error.
/***********************************************************************/ /* I N C L U S I O N D E L I B R E R I A S E S T A N D A R D */ /***********************************************************************/ #include <stdio.h> #include <stdlib.h> /*******************************************************************/ /* I N C L U S I O N D E L I B R E R I A S L O C A L E S */ /*******************************************************************/ #include "error.h" /* Variable Global Externa */ extern int errno; /* Error Fatal: Imprime un mensaje de Error y finaliza el proceso Entrada: mensaje = Mensaje de Error Salida: Ninguna */ void ErrorFatal(mensaje) char *mensaje; { fprintf(stderr, "### Error numero %d :\n", errno); fprintf(stderr, "%s\n", mensaje); perror("Error"); exit(-1); } /* Error normal: Imprime un mensaje de Error y regresa. Entrada: mensaje = Mensaje de Error Salida: Ninguna */ void Error(mensaje) char *mensaje; { fprintf(stderr, "### Error numero %d :\n", errno); fprintf(stderr, "%s\n", mensaje); perror("Error"); return; }
TCP.C : Definición de funciones de gestión de sockets TCP.
/********************************************* ** FUNCIONES DE COMUNICACION VIA SOCKET TCP ** **********************************************/ /************************************************************************/ /* I N C L U S I O N D E L I B R E R I A S E S T A N D A R D */ /************************************************************************/ #include <string.h> /*******************************************************************/ /* I N C L U S I O N D E L I B R E R I A S L O C A L E S */ /*******************************************************************/ #include "tipos.h" #include "include.h" #include "error.h" /* Creacion de un Socket de Escucha TCP para un Servidor Entrada: puerto = Puerto de Conexion Salida: DirServ = Estructura de Direccion Internet return = Identificador del Socket Creado */ int CrearSocketTCP(u_short puerto, TDireccion *DirServ) { char NombreHost[128]; char mensajeError[80]; int sockfd; struct hostent *hostinfo; /* Localizar el Nombre del Host Local */ if (gethostname(NombreHost, sizeof(NombreHost)) == -1) ErrorFatal("Nombre del host local inaccesible\n"); # ifdef DEBUG printf("Servidor: El nombre del host para este socket es '%s'\n", NombreHost); # endif # ifndef HOST_LOCAL /* Obtener informacion del Host */ hostinfo = gethostbyname(NombreHost); if (hostinfo == NULL) { sprintf(mensajeError, "El host '%s' no existe\n", NombreHost); ErrorFatal(mensajeError); } # endif /* Creacion del Socket de Escucha TCP Internet */ if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) <0) ErrorFatal("Servidor: No puede abrir socket\n"); /* Obtencion de la Direccion del Host */ /* bzero((char *) DirServ, sizeof(*DirServ)); */ memset((char *) DirServ, 0, sizeof(*DirServ)); DirServ->sin_family = AF_INET; # ifndef HOST_LOCAL (DirServ->sin_addr).s_addr = ((struct in_addr *) (hostinfo->h_addr))->s_addr; # else (DirServ->sin_addr).s_addr = htonl(INADDR_ANY); # endif DirServ->sin_port = htons(puerto); return(sockfd); } /* Establece una Conexion con un Servidor Remoto via Socket TCP Internet Entrada: puerto = Puerto de Conexion hserv = Nombre del Host Servidor al que conectar Salida: return = Identificador del Socket Creado */ int OpenServidor(hserv, puerto) char *hserv; int puerto; { TDireccion DirServ; int SocketConsulta; /* Creacion del Socket */ if ( (SocketConsulta = socket(AF_INET, SOCK_STREAM, 0)) <0) { ErrorFatal("Cliente: No pudo abrir Socket\n"); return -1; } /* Preparacion de informacion sobre el servidor */ /* bzero((char *) &DirServ, sizeof(DirServ)); */ memset((char *) &DirServ, 0, sizeof(DirServ)); DirServ.sin_family = AF_INET; DirServ.sin_addr.s_addr = inet_addr(hserv); DirServ.sin_port = htons(puerto); /* Conexion con el Servidor */ if (connect(SocketConsulta, (struct sockaddr *)&DirServ, sizeof(DirServ))<0) { ErrorFatal("Cliente: No pudo conectar con Servidor\n"); return -1; } return SocketConsulta; } /* Cierre de una Conexion con un Servidor Remoto via Socket TCP Internet Entrada: Socket = Id. del Socket a cerrar Salida: return = 0 (Ok) o -1(Error) */ int CloseServidor(Socket) int Socket; { if (close(Socket) == -1) { Error("Error en el Cierre del Socket\n"); return -1; } return 0; } /* Enviar una Trama a traves de un Socket Entrada: Socket = Id. del Socket Tipo = Tipo de la Trama Datos = Informacion a enviar Salida: return = 0 (Ok) o -1(Error) */ int EnviarTrama(Socket, Tipo, Datos) int Socket; char Tipo; char *Datos; { static char Trama[MAX_LONG_TRAMA+2]; static int ltrama; Trama[0] = Tipo; Trama[1] = '\0'; strcat(Trama, Datos); ltrama = strlen(Datos) + 1; /* if ( write(Socket, Trama, ltrama) != ltrama ) */ if ( write(Socket, Trama, MAX_LONG_TRAMA) != MAX_LONG_TRAMA ) ErrorFatal("Error al Enviar Trama!!!\n"); return 0; } /* Reciber una trama enviada por el Servidor a traves de un Socket Entrada: Socket = Descriptor del socket del que se va a leer Salida: Datos = Datos de la trama return = Tipo de Trama o -1 si error */ int RecibirTrama(Socket, Datos) int Socket; char *Datos; { static char Trama[MAX_LONG_TRAMA+2]; int lTrama; char Tipo; if ( (lTrama = read(Socket, Trama, MAX_LONG_TRAMA)) == -1 ) { Error("Error al Recibir Trama!!!\n"); return -1; } Trama[lTrama] = '\0'; if ( lTrama == 0 ) { Tipo = -1; strcpy(Datos, ""); } else { Tipo = Trama[0]; strcpy(Datos, Trama+1); } return Tipo; }
TIEMPO.C : Definición de funciones de gestión de tiempos.
#include "tiempo.h" /* Proposito: Calcula la diferencia t2 - t1 de tiempo entre los tiempos dados. Entrada: t1 = Tiempo en segundos y microsegundos t2 = Tiempo en segundos y microsegundos Salida : d = Diferencia en segundos y microsegundos (ajustada) */ void DiffTime(struct timeval *t1, struct timeval *t2, struct timeval *d) { d->tv_sec = t2->tv_sec - t1->tv_sec; d->tv_usec = t2->tv_usec - t1->tv_usec; AdjustTime(d); } /* Proposito: Calcula la suma t2 + t1 de tiempos entre los tiempos dados. Entrada: t1 = Tiempo en segundos y microsegundos t2 = Tiempo en segundos y microsegundos Salida : d = Suma en segundos y microsegundos (ajustada) */ void AddTime(struct timeval *t1, struct timeval *t2, struct timeval *d) { d->tv_sec = t2->tv_sec + t1->tv_sec; d->tv_usec = t2->tv_usec + t1->tv_usec; AdjustTime(d); } /* Proposito: Calcula la division del tiempo t1 entre el numero n. Entrada: t1 = Tiempo en segundos y microsegundos Salida : d = Suma en segundos y microsegundos (ajustada) */ void DivTimeInt(struct timeval *t1, long n, struct timeval *d) { long resto = t1->tv_sec % n; d->tv_sec = t1->tv_sec / n; d->tv_usec = (t1->tv_usec + (resto * 1000000L)) / n ; AdjustTime(d); } /* Proposito: Ajustar el tiempo dado. Entrada: d = Tiempo en segundos y microsegundos Salida : d = Tiempo en segundos y microsegundos (ajustado) */ void AdjustTime(struct timeval *d) { if (d->tv_usec >= 1000000L) { d->tv_sec++; d->tv_usec-= 1000000L; } else if (d->tv_usec < 0) { d->tv_sec--; d->tv_usec+= 1000000L; } } /* Visualiza el tiempo actual y el acumulado */ void PrintTime(char *mensaje, struct timeval *t1, struct timeval *t2) { static struct timeval d; printf("%s\n", mensaje); gettimeofday(t2, NULL); /* printf("\tTime = %d s : %d ms\n", t2->tv_sec, t2->tv_usec); */ DiffTime(t1, t2, &d); printf("\tAcumTime = %d s : %d ms\n", d.tv_sec, d.tv_usec); fflush(stdout); /* *t1 = *t2; */ }
GETSTATS.C : Definición de funciones de gestión de estadísticas.
/* ESTADISTICAS DE TIEMPO */ #include <stdio.h> #include <sys/time.h> #include <sys/times.h> #include <sys/resource.h> #include <unistd.h> #include "getstats.h" /* Compilacion con una de las dos formas de calcular estadisticas: */ /* #define WITH_TIMES */ #ifdef WITH_TIMES /* Proposito: Obtener estadisticas de tiempo hasta este instante. Entrada: Ninguna Salida: user = Tiempo en modo usuario en seg. empleado por el proceso. system = Tiempo en modo sistema en seg. empleado por el proceso. real = Ticks de reloj que han transcurrido. */ void gettimes(unsigned long *user, unsigned long *system, unsigned long *real) { struct tms buffer; *real = times(&buffer); *user = buffer.tms_utime; *system = buffer.tms_stime; } /* Proposito: Imprimir estadisticas de tiempo, calculando la diferencia a partir de dos tiempos pasados como argumentos. Entrada: f = Fichero de salida de los datos. user = Vector de 2 Tiempos en modo usuario en seg. empleados por el proceso. system = Vector de 2 Tiempos en modo sistema en seg. empleados por el proceso. real = Vector de 2 Tiempos en ticks de reloj. Salida: Ninguna */ void printtimes(FILE *f, unsigned long *user, unsigned long *system, unsigned long *real) { fprintf(f, "Usuario: %ld-%ld = %lf\n", user[1] , user[0], (user[1]-user[0])*1000.0/60.0); fprintf(f, "Sistema: %ld-%ld = %lf\n", system[1], system[0], (system[1]-system[0])*1000.0/60.0); fprintf(f, "Real: %ld-%ld = %lf\n", real[1], real[0], (real[1]-real[0])*1000.0/60.0); } /* Proposito: Obtener estadisticas de tiempo hasta este instante. Entrada: Ninguna Salida: e = Estructura de datos con informacion sobre tiempo en modo usuario, modo sistema y ticks de reloj transcurridos hasta el momento. */ void ObtenerTiempo(estad_t *e) { struct tms buffer; e->t_real = times(&buffer); e->t_user = buffer.tms_utime; e->t_system = buffer.tms_stime; } /* Proposito: Imprimir estadisticas de tiempo, calculando la diferencia a partir de las dos estructuras FINAL-INICIAL pasadas como argumentos. Entrada: f = Fichero de salida de los datos. e0 = Estructura de datos inicial sobre tiempo de usuario, de sistema y real empleados por el proceso. e1 = Estructura de datos final sobre tiempo de usuario, de sistema y real empleados por el proceso. */ void PrintTiempos(FILE *f, estad_t *e0, estad_t *e1) { fprintf(f, "Usuario: %ld-%ld = %lf\n", e1->t_user , e0->t_user, (e1->t_user - e0->t_user)*1000.0/60.0); fprintf(f, "Sistema: %ld-%ld = %lf\n", e1->t_system, e0->t_system, (e1->t_system - e0->t_system)*1000.0/60.0); fprintf(f, "Real: %ld-%ld = %lf\n", e1->t_real, e0->t_real, (e1->t_real - e0->t_real)*1000.0/60.0); } #else /* No WITH_TIMES */ /* Proposito: Obtener estadisticas de tiempo hasta este instante. Entrada: Ninguna Salida: ru = Datos sobre utilizacion de recursos por el proceso. user = Tiempo en modo usuario en miliseg. empleado por el proceso. system = Tiempo en modo sistema en miliseg. empleado por el proceso. real = Tiempo actual en miliseg. */ void getstats(struct rusage *ru, unsigned long *user, unsigned long *system, unsigned long *real) { int res; struct timeval tv; res = gettimeofday(&tv, NULL); if (res<0) { *user = *system = *real = -1; return; } res = getrusage(RUSAGE_SELF, ru); if (res<0) *user = *system = -1; else { *user = (ru->ru_utime.tv_sec % 1000000) * 1000 + ru->ru_utime.tv_usec/1000; *system = (ru->ru_stime.tv_sec % 1000000) * 1000 + ru->ru_stime.tv_usec/1000; } *real = (tv.tv_sec % 1000000) * 1000 + tv.tv_usec/1000; } /* Proposito: Imprimir estadisticas de tiempo, calculando la diferencia a partir de dos tiempos pasados como argumentos. Entrada: f = Fichero de salida de los datos. ru = Vector de 2 datos sobre utilizacion de recursos por el proceso. user = Vector de 2 Tiempos en modo usuario en miliseg. empleados por el proceso. system = Vector de 2 Tiempos en modo sistema en miliseg. Empleados por el proceso. real = Vector de 2 Tiempos en miliseg. Salida: Ninguna */ void printstats(FILE *f, struct rusage *ru, unsigned long *user, unsigned long *system, unsigned long *real) { fprintf(f, "Usuario: %ld-%ld = %ld\n", user[1] , user[0], user[1]-user[0]); fprintf(f, "Sistema: %ld-%ld = %ld\n", system[1], system[0], system[1]-system[0]); fprintf(f, "Real: %ld-%ld = %ld\n", real[1], real[0], real[1]-real[0]); fprintf(f, "Total Faltas Pagina: %ld-%ld = %ld\n", ru[1].ru_minflt + ru[1].ru_majflt, ru[0].ru_minflt + ru[0].ru_majflt, ru[1].ru_minflt + ru[1].ru_majflt - ru[0].ru_minflt - ru[0].ru_majflt); fprintf(f, "Cambios de contexto voluntarios: %ld-%ld = %ld\n", ru[1].ru_nvcsw, ru[0].ru_nvcsw, ru[1].ru_nvcsw - ru[0].ru_nvcsw); fprintf(f, "Cambios de contexto involuntarios: %ld-%ld = %ld\n", ru[1].ru_nivcsw, ru[0].ru_nivcsw, ru[1].ru_nivcsw - ru[0].ru_nivcsw); } /* Proposito: Obtener estadisticas de tiempo hasta este instante. Entrada: Ninguna Salida: e = Estructura de datos sobre utilizacion de recursos, tiempo de usuario, de sistema y real empleados por el proceso. */ void getestad(estad_t *e) { struct timeval tv; if (gettimeofday(&tv, NULL) <0) { e->t_user = e->t_system = e->t_real = -1; return; } if (getrusage(RUSAGE_SELF, &e->ru)<0) e->t_user = e->t_system = -1; else { e->t_user = (e->ru.ru_utime.tv_sec % 1000000) * 1000 + e->ru.ru_utime.tv_usec/1000; e->t_system = (e->ru.ru_stime.tv_sec % 1000000) * 1000 + e->ru.ru_stime.tv_usec/1000; } e->t_real = (tv.tv_sec % 1000000) * 1000 + tv.tv_usec/1000; } /* Proposito: Imprimir estadisticas de tiempo, calculando la diferencia a partir de las dos estructuras FINAL-INICIAL pasadas como argumentos. Entrada: f = Fichero de salida de los datos. e0 = Estructura de datos inicial sobre utilizacion de recursos, tiempo de usuario, de sistema y real empleados por el proceso. e1 = Estructura de datos final sobre utilizacion de recursos, tiempo de usuario, de sistema y real empleados por el proceso. */ void printestad(FILE *f, estad_t *e0, estad_t *e1) { fprintf(f, "Usuario: %ld-%ld = %ld\n", e1->t_user , e0->t_user, e1->t_user - e0->t_user); fprintf(f, "Sistema: %ld-%ld = %ld\n", e1->t_system, e0->t_system, e1->t_system - e0->t_system); fprintf(f, "Real: %ld-%ld = %ld\n", e1->t_real, e0->t_real, e1->t_real - e0->t_real); fprintf(f, "Total Faltas Pagina: %ld-%ld = %ld\n", e1->ru.ru_minflt + e1->ru.ru_majflt, e0->ru.ru_minflt + e0->ru.ru_majflt, e1->ru.ru_minflt + e1->ru.ru_majflt - e0->ru.ru_minflt - e0->ru.ru_majflt); fprintf(f, "Cambios de contexto voluntarios: %ld-%ld = %ld\n", e1->ru.ru_nvcsw, e0->ru.ru_nvcsw, e1->ru.ru_nvcsw - e0->ru.ru_nvcsw); fprintf(f, "Cambios de contexto involuntarios: %ld-%ld = %ld\n", e1->ru.ru_nivcsw, e0->ru.ru_nivcsw, e1->ru.ru_nivcsw - e0->ru.ru_nivcsw); } #endif /* WITH_TIMES */
GETARGS.C : Definición de funciones de obtención de argumentos y otras.
#include <sys/types.h> #include <sys/ipc.h> #include "getargs.h" /* Datos relacionados con la version y sintaxis del programa */ extern const char VERSION[]; extern const char SINTAX[]; #ifndef HILOS /* Definicion de Identificadores de Claves de Recursos del Sistema */ #define SHMEM0_KEY ((key_t)188760L) #define SHMEM1_KEY ((key_t)188761L) #define SHMEM2_KEY ((key_t)188762L) #define SHMEM3_KEY ((key_t)188763L) #endif /* Obtener la linea de argumentos */ void GetArgs(int argc, char *argv[], int *n, int *nsist) { printf(VERSION); /* Comprobar si se solicita ayuda */ if (argc > 1) { if ( strcmp(argv[1],"-?") == 0 || strcmp(argv[1],"-h") == 0 ) { printf(SINTAX, argv[0]); exit(0); } } /* Establecer valores por defecto */ *n = TAM_MATRIZ; *nsist = N_SIST; /* Obtenemos la lista de argumentos */ switch(argc) { case 3: *nsist = atoi(argv[2]); if (*nsist<1 || *nsist>N_SIST) *nsist = N_SIST; case 2: *n = atoi(argv[1]); if (*n<1 || *n>TAM_MATRIZ) *n = TAM_MATRIZ; case 1: break; default: printf(SINTAX, argv[0]); printf("El numero de argumentos es incorrecto!\n"); exit(1); } } /* Obtener la linea de argumentos: segunda version */ void GetArgs2(int argc, char *argv[], int *n, int *nsist, int *nhilos) { printf(VERSION); /* Comprobar si se solicita ayuda */ if (argc > 1) { if ( strcmp(argv[1],"-?") == 0 || strcmp(argv[1],"-h") == 0 ) { printf(SINTAX, argv[0]); exit(0); } } /* Establecer valores por defecto */ *n = TAM_MATRIZ; *nsist = N_SIST; *nhilos = *n; /* Obtenemos la lista de argumentos */ switch(argc) { case 4: *nsist = atoi(argv[3]); if (*nsist<1 || *nsist>N_SIST) *nsist = N_SIST; case 3: *n = atoi(argv[2]); if (*n<1 || *n>TAM_MATRIZ) *n = TAM_MATRIZ; case 2: *nhilos = atoi(argv[1]); if (*nhilos<1 || *nhilos>*n) *nhilos = *n; case 1: break; default: printf(SINTAX, argv[0]); printf("El numero de argumentos es incorrecto!\n"); exit(1); } } /* Inicializacion de los datos de los sistemas: Ax = b A = Matriz triangular inferior x = 1 vector de incognitas para cada sist. b = 1 vector de term.indep. para cada sist. */ void init_data(datos_t *d, int n, int nsist) { int i,j; for (i = 0; i<n; i++) { for (j = 0; j<n; j++) { if (i - j >= 0) d->A(i,j) = 2.5; else d->A(i,j) = 0.0; } } for (i = 0; i<n; i++) { for (j = 0; j<nsist; j++) { d->b(i,j) = 5.0 * (i+1) * (j+1); d->x(i,j) = 0.0; } } } /* Imprimir las soluciones del sistema */ void PrintSolucion(datos_t *d, int n, int nsist) { int i,j; /* Imprimir las soluciones */ printf("SOLUCION:\n"); printf("-----------\n"); for (i = 0; i<n; i++) { for (j = 0; j<nsist; j++) printf(" %.8lf", d->x(i,j)); printf("\n"); } } /* Proposito: Crear zona de memoria compartida por los procesos. Entrada: n = Tamano del sistema. nsist = No. de sistemas. Salida: shmem_id[] = Vector de identificadores de memoria compartida. return = Puntero a la zona de memoria compartida. */ datos_t *CrearMemoria(int *shmem_id, int n, int nsist) { datos_t *d; #ifndef HILOS /* Crear memoria compartida */ if ((shmem_id[0] = shmget(SHMEM0_KEY, sizeof(datos_t), 0666 | IPC_CREAT)) <0) ErrorFatal("No se pudo crear la memoria compartida"); /* Establecer el acceso a la memoria compartida para Datos */ if ((d = (datos_t *) shmat(shmem_id[0], (char *)0, 0)) == (datos_t *) -1) ErrorFatal("No se pudo enlazar con la memoria compartida"); if ((shmem_id[1] = shmget(SHMEM1_KEY, n*n*sizeof(double), 0666 | IPC_CREAT)) <0) ErrorFatal("No se pudo crear la memoria compartida para A"); /* Establecer el acceso a la memoria compartida */ if ((d->A = (double *) shmat(shmem_id[1], (char *)0, 0)) == (double *) -1) ErrorFatal("No se pudo enlazar con la memoria compartida"); if ((shmem_id[2] = shmget(SHMEM2_KEY, n*nsist*sizeof(double), 0666 | IPC_CREAT)) <0) ErrorFatal("No se pudo crear la memoria compartida para x"); /* Establecer el acceso a la memoria compartida */ if ((d->x = (double *) shmat(shmem_id[2], (char *)0, 0)) == (double *) -1) ErrorFatal("No se pudo enlazar con la memoria compartida"); if ((shmem_id[3] = shmget(SHMEM3_KEY, n*nsist*sizeof(double), 0666 | IPC_CREAT)) <0) ErrorFatal("No se pudo crear la memoria compartida para b"); /* Establecer el acceso a la memoria compartida */ if ((d->b = (double *) shmat(shmem_id[3], (char *)0, 0)) == (double *) -1) ErrorFatal("No se pudo enlazar con la memoria compartida"); #else /* HILOS definida */ if ( (d = (datos_t *) malloc(sizeof(datos_t))) == (datos_t *)NULL ) ErrorFatal("No se pudo crear la memoria compartida"); if ( (d->A = (double *) calloc(n*n, sizeof(double))) == (double *) NULL ) ErrorFatal("No se pudo crear la memoria compartida para A"); if ( (d->x = (double *) calloc(n*nsist, sizeof(double))) == (double *) NULL ) ErrorFatal("No se pudo crear la memoria compartida para x"); if ( (d->b = (double *) calloc(n*nsist, sizeof(double))) == (double *) NULL ) ErrorFatal("No se pudo crear la memoria compartida para b"); #endif return(d); } /* Proposito: Destruir zona de memoria compartida por los procesos Entrada: shmem_id = Vector de identif. de memoria compartida. d = Puntero a la zona de memoria compartida. */ void DestruirMemoria(int *shmem_id, datos_t *d) { #ifndef HILOS /* Destruir memoria compartida */ if ( shmdt((char *)d->A) <0 ) ErrorFatal("No se pudo desenlazar la memoria compartida"); if ( shmctl(shmem_id[1], IPC_RMID, (struct shmid_ds *)0) <0 ) ErrorFatal("No se pudo liberar la memoria compartida"); if ( shmdt((char *)d->x) <0 ) ErrorFatal("No se pudo desenlazar la memoria compartida"); if ( shmctl(shmem_id[2], IPC_RMID, (struct shmid_ds *)0) <0 ) ErrorFatal("No se pudo liberar la memoria compartida"); if ( shmdt((char *)d->b) <0 ) ErrorFatal("No se pudo desenlazar la memoria compartida"); if ( shmctl(shmem_id[3], IPC_RMID, (struct shmid_ds *)0) <0 ) ErrorFatal("No se pudo liberar la memoria compartida"); if ( shmdt((char *)d) <0 ) ErrorFatal("No se pudo desenlazar la memoria compartida"); if ( shmctl(shmem_id[0], IPC_RMID, (struct shmid_ds *)0) <0 ) ErrorFatal("No se pudo liberar la memoria compartida"); #else free((void *)d->A); free((void *)d->x); free((void *)d->b); free((void *)d); #endif }
SEMAFORO.C : Definición de funciones de gestión de semáforos.
#include <stdio.h> #include <errno.h> #include "semaforo.h" #include "error.h" extern int errno; #define BIGCOUNT 10000 /* Valor inicial del contador de procesos */ /* Definicion del vector de operaciones de semaforo para semop() */ /* OPERACION DE BLOQUEO */ static struct sembuf op_lock[2] = { 2, 0, 0, /* Bloqueo Semaforo real */ 2, 1, SEM_UNDO /* Bloqueo Semaforo para control de huerfanos */ }; /* OPERACION DE CREACION */ static struct sembuf op_endcreate[2] = { 1, -1, SEM_UNDO, /* Creacion Semaforo real */ 2, -1, SEM_UNDO /* Creacion Semaforo para control de huerfanos */ }; /* OPERACION DE APERTURA */ static struct sembuf op_open[1] = { 1, -1, SEM_UNDO /* Abrir Semaforo real */ }; /* OPERACION DE CIERRE */ static struct sembuf op_close[3] = { 2, 0, 0, /* Cerrar Semaforo real */ 2, 1, SEM_UNDO, 1, 1, SEM_UNDO }; /* OPERACION DE DESBLOQUEO */ static struct sembuf op_unlock[1] = { 2, -1, SEM_UNDO /* Desbloqueo Semaforo real */ }; /* OPERACION DE INCREMENTO O DECREMENTO */ static struct sembuf op_op[1] = { 0, 99, SEM_UNDO /* Incremento o Decremento Semaforo real */ }; /* union { int val; struct semid_ds *buf; ushort *array; } semctl_arg; */ union semun semctl_arg; /* Proposito: Crear un semaforo con un valor inicial especificado. Si el semforo ya existe, no se inicializa. Entrada: key = Clave del semaforo initval = Valor inicial del semaforo Salida: return = ID del semaforo (Ok) o -1 (error) */ int sem_create(key_t key, int initval) { register int id, semval; if (key == IPC_PRIVATE) return (-1); /* No se intenta para semaforos privados */ else if (key == (key_t) -1) return (-1); /* Garantizamos que el semaforo no esta siendo creado en otro proceso */ while (1) { if ( (id = semget(key, 3, 0666 | IPC_CREAT)) <0) return (-1); /* Problemas de permiso o tablas sistema llenas */ if (semop(id, &op_lock[0], 2) < 0) { if (errno == EINVAL) continue; ErrorFatal("Error Semaforo: No se puede bloquear"); } break; } /* Obtenemos el valor del contador de procesos para el semaforo */ semctl_arg.val = 0; if ( (semval = semctl(id, 1, GETVAL, semctl_arg)) <0) ErrorFatal("Error Semaforo: No se puede obtener valor"); /* Si no hay procesos asignados al semaforo, le inicializamos */ if (semval == 0) { semctl_arg.val = initval; if (semctl(id, 0, SETVAL, semctl_arg) <0) ErrorFatal("Error Semaforo: No se puede asignar valor en [0]"); semctl_arg.val = BIGCOUNT; if (semctl(id, 1, SETVAL, semctl_arg) <0) ErrorFatal("Error Semaforo: No se puede asignar valor en [1]"); } /* Decrementamos el contador de procesos y liberamos el bloqueo */ if (semop(id, &op_endcreate[0], 2) <0) ErrorFatal("Error Semaforo: No se puede crear"); return (id); } /* Proposito: Abrir un semaforo que ya existe para su utilizacion. Entrada: key = Clave del semaforo Salida: return = ID del semaforo (Ok) o -1 (error) */ int sem_open(key_t key) { register int id; if (key == IPC_PRIVATE) return (-1); /* No se intenta para semaforos privados */ else if (key == (key_t) -1) return (-1); if ( (id = semget(key, 3, 0)) <0) return (-1); /* Semaforo no existe o tablas sistema llenas */ /* Decrementamos el contador de procesos sin necesidad de bloqueo */ if (semop(id, &op_open[0], 1) <0) ErrorFatal("Error Semaforo: No se puede abrir"); return (id); } /* Proposito: Eliminar un semaforo que existe. Entrada: id = ID del semaforo Salida: Ninguna */ void sem_remove(int id) { semctl_arg.val = 0; if (semctl(id, 0, IPC_RMID, semctl_arg) <0) ErrorFatal("Error Semaforo: No puede eliminar"); } /* Proposito: Cerrar un semaforo que fue abierto con sem_open() o sem_create(). Entrada: id = ID del semaforo Salida: Ninguna */ void sem_close(int id) { register int semval; /* Bloqueamos el semaforo e incrementamos el contador de procesos */ if (semop(id, &op_close[0], 3) <0) ErrorFatal("Error Semaforo: No puedo realizar operacion"); /* Obtenemos el contador de procesos, para ver si es la ultima referencia al semaforo */ semctl_arg.val = 0; if ((semval = semctl(id, 1, GETVAL, semctl_arg)) <0) ErrorFatal("Error Semaforo: No se puede obtener valor"); if (semval > BIGCOUNT) ErrorFatal("Error Semaforo: sem[1] > BIGCOUNT"); else if (semval == BIGCOUNT) sem_remove(id); else if (semop(id, &op_unlock[0], 1) <0) ErrorFatal("Error Semaforo: No se puede desbloquear"); } /* Proposito: Realizar una operacion sobre un semaforo. Entrada: id = ID del semaforo value = Valor a incrementar o decrementar al semaforo Salida: Ninguna */ void sem_op(int id, int value) { if ((op_op[0].sem_op = value) == 0) ErrorFatal("Error Semaforo: El valor 0 no se puede incrementar al semaforo"); if (semop(id, &op_op[0], 1) <0) ErrorFatal("Error Semaforo: No se puede realizar operacion"); } /* Proposito: Operacion wait con semaforo. Operacion P de Dijkstra. Entrada: id = ID del semaforo Salida: Ninguna */ /* void sem_wait(int id) { sem_op(id, -1); } */ /* Proposito: Operacion signal con semaforo. Operacion V de Dijkstra. Entrada: id = ID del semaforo Salida: Ninguna */ /* void sem_signal(int id) { sem_op(id, 1); } */
MUTEX.C : Definición de funciones de simulación de mútex.
#include "mutex.h" /* Proposito: Inicializar un mutex. Entrada: mutex = Mutex a inicializar mutex_key = Clave identificadora del semaforo asociado. Salida : mutex = Mutex inicializado. return = -1 (Error) o 0 (Ok) */ int mutex_init(mutex_t *mutex, key_t mutex_key) { if ((*mutex = (mutex_t) sem_create(mutex_key, 1)) <0) return(-1); return(0); } /* Proposito: Destruir un mutex. Entrada: mutex = Mutex a destruir Salida : return = -1 (Error) o 0 (Ok) */ int mutex_destroy(mutex_t *mutex) { sem_close( (int)*mutex ); return(0); } /* Proposito: Bloquear un mutex previamente inicializado. Entrada: mutex = Mutex a bloquear Salida : return = -1 (Error) o 0 (Ok) */ int mutex_lock(mutex_t *mutex) { sem_wait( (int)*mutex ); return(0); } /* Proposito: Liberar un mutex previamente inicializado. Entrada: mutex = Mutex a desbloquear Salida : return = -1 (Error) o 0 (Ok) */ int mutex_unlock(mutex_t *mutex) { sem_signal( (int)*mutex ); return(0); }
COND.C : Definición de funciones de simulación de variables de condición.
#include "cond.h" /* Proposito: Inicializar una variable de condicion. Entrada: varcond = Variable de condicion a inicializar. cond_key = Clave identificadora del semaforo asociado. Salida: varcond = Variable de condicion inicializada. return = -1 (Error) o 0 (Ok) */ int cond_init(cond_t *varcond, key_t cond_key) { varcond->delay_cont = 0; if ((varcond->delay = sem_create(cond_key, 0)) <0) return(-1); return(0); } /* Proposito: Destruir una variable de condicion. Entrada: varcond = Variable de condicion. Salida: return = -1 (Error) o 0 (Ok) */ int cond_destroy(cond_t *varcond) { if ( varcond->delay_cont >0 ) return(-1); sem_close( varcond->delay ); return(0); } /* Proposito: Despierta a los procesos que esperan por una variable de condicion. Entrada: varcond = Variable de condicion por la que se espera. Salida: return = -1 (Error) o 0 (Ok) */ int cond_signal(cond_t *varcond) { int i; for (i = 1; i <= varcond->delay_cont; i++) sem_signal(varcond->delay); return(0); } /* Proposito: Espera por una variable de condicion. Entrada: varcond = Variable de condicion por la que se espera. mutex = Mutex bloqueado, asociado a la var.de condicion. Salida: return = -1 (Error) o 0 (Ok) */ int cond_wait(cond_t *varcond, mutex_t *mutex) { varcond->delay_cont++; mutex_unlock(mutex); sem_wait(varcond->delay); mutex_lock(mutex); varcond->delay_cont--; return(0); }