Linux
Booteo – Threads y Pipes
Booting the kernel1. Un loader encuentra la imagen de kernel en el
disco, lo carga en memoria y comienza a ejecutarla
2. El kernel inicializa los dispositivos y sus drivers.3. El kernel monta el filesystem /4. El kernel ejecuta el programa init5. El proceso init ejecuta el resto de los procesos
indicados6. El ultimo proceso que el init ejecuta como parte
de la secuencia de booteo es el proceso de login.
GRUB Grand Unified Bootloader Permite navegar por los filesystems sin
cargar el kernel Tiene un minishell que permite hacer
multiples booteos con parámetros distintos.
Ejemplo: root (hd0,2) kernel /boot/vmlinuz root=/dev/hda3 -s noacpi initrd /boot/initrd boot
El proceso Init Este programa se encuentra en /sbin Ejecuta programas en un orden específico La mayoría de los linux usan el estilo
System V, algunos otros usan el de BSD. Existen runlevels (0 a 6), que indican
cuales son los procesos que deberían estar en ejecución. (el kernel ejecuta o termina servicios según el runlevel indicado)
/etc/inittab /etc/rc*.d: Snntexto y Knntexto
/etc/inittab Contiene lineas del estilo:
Id: 5:initdefault: Esta linea indica que el runlevel por default es el 5
l5:5:wait:/etc/rc.d/rc 5 Esta linea dispara la mayoría de las configuraciones y
servicios de los directorios /etc/rc*.d y /etc/init.d Wait : Indica que ejecuta todos los comandos y quede a
la espera de su finalización. Respawn: Siempre existe una copia del programa
ejecutando 1:2345:respawn:/sbin/mingetty tty1 El programa getty provee el prompt de login.
Sysinit : Todo aquello que se debe ejecutar antes de entrar en los runlevels.
Shutting Down Shutdown –r +10
Pasado el tiempo de gracia, el programa shutdown le indica a init que cambie a runlevel 0 para halt o a runlevel 6 para reboot.
Entrando en runlevel 0 o 6, el init mata todo proceso que puede. Los primeros comandos del rc0 o rc6, bloquean
archivos de sistema, luego desmontan los filesystems distintos a root, remonta el root como solo lectura, graba los buffers con el programa sync y por ultimo ejecuta halt, reboot o poweroff.
Algunos archivos especiales /bin/sh, /etc/bashrc, /etc/profile,
/etc/profile.d /etc/resolv.conf, /etc/nsswitch, /etc/hosts,
/etc/hosts.allow, /etc/hosts.deny /etc/passwd, /etc/shadow /etc/fstab /etc/mtab /etc/inittab, /etc/rc*.d, /etc/init.d /etc/ld.so.conf
Pipes Los pipes, son archivos especiales que
se crean para intercambiar información entre procesos.
Normalmente se los puede usar desde la linea de comandos (con el símbolo “|” ): who | more
Esto le indica al interprete de comandos que ejecute dos procesos “who y more” y una la salida del comando who a la entrada del comando more.
Estructura de Pipes
Pipes #include <unistd.h> int dup2(int fd1, int fd2);
Pipes (who | more)/* Archivo del programa whomore.c */main() { int fds[2] pipe(fds); /* Hijo1 reconecta stdin a parte baja del pipe y cierra alta */ if (fork() == 0) { dup2(fds[0], 0); close(fds[1]); execlp(“more”,”more”,0); } else { /* Hijo2 reconecta stdout a parte alta del pipe y cierra baja */ if ( fork() == 0 ) {
dup2(fds[1], 1);close(fds[0]);execlp(“who”, “who”, 0);
} else { /* padre cierra ambas partes y espera a los hijos */
close(fds[0]);close(fds[1]);wait(0);wait(0):
}}
Otro Ejemplo con pipes int main(int argc, char *argv[]) { int pfd[2]; pid_t cpid; char buf[80]; if (pipe(pfd) == -1) { perror("pipe"); exit(EXIT_FAILURE); } write(pfd[1], argv[0], strlen(argv[0])); cpid = fork(); if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (cpid == 0) { while (read(pfd[0], &buf, 1) > 0) { .... write(pfd[1], argv[0], strlen(argv[0])); } close(pfd[0]); _exit(EXIT_SUCCESS); }
Posix Threads Un thread es una lista de instrucciones
que puede ser planificado para ejecutar por el sistema operativo
Normalmente se trata de un procedimiento dentro de un programa que puede ejecutarse independientemente del programa.
Como se implementa en UNIX. IEEE POSIX 1003.1c standard (1995)
Proceso vs Thread Un proceso en LINUX tiene asociado:
Id de proceso, id de grupo de proceso, id de grupo, id de usuario
Mapa de Memoria Ambiente Directorio de ejecución Instrucciones de programa Registros Stack Heap Descriptores de Archivos Atenciones a señales Librerías compartidas Herramientas de comunicación
cola de mensajes, pipes, semáforos o memoria compartida
Proceso vs Thread
Pthreads El Api de Pthreads esta dividido en:
Manejo de Threads Mutex Variables de Condición
Convensiones: pthread_ (rutinas) // pthread_attr_ (atributos) pthread_mutex_ (mutex) // pthread_mutexattr_ pthread_cond_ (cond. Var) // pthread_condattr_ pthread_key_ (data keys)
Compilacion con pthreads gcc -pthread
Rutinas de Pthreads Rutinas:
pthread_create (thread,attr,start_routine,arg)
pthread_exit (status) pthread_attr_init (attr) pthread_attr_destroy (attr)
Atributos: pthread_attr_init pthread_attr_destroy
Pthread Ejemplo #include <pthread.h> #include <stdio.h> #include <stdlib.h> #define NUM_THREADS5
void *ImprimirHola(void *threadid) { int tid; tid = (int)threadid; printf("Hola Mundo! Soy el thread #%d!\n", tid); pthread_exit(NULL); }
Pthread Ejemplo int main(int argc, char *argv[]) { pthread_t threads[NUM_THREADS]; int rc, t; for(t=0;t<NUM_THREADS;t++){ printf("In main: creating thread %d\n", t); rc = pthread_create(&threads[t], NULL, ImprimirHola,
(void *)t); if (rc){ printf("ERROR; No se pudo crear thread nro %d\n", rc); exit(-1); } } pthread_exit(NULL); }
Pthreads: Pasaje de argumentos
struct thread_data{ int thread_id; int sum; char *message; };
struct thread_data thrd_data_A[NUM_THREADS];
void *ImprimirHola(void *threadarg) { struct thread_data *my_data; ... my_data = (struct thread_data *) threadarg; taskid = my_data->thread_id; sum = my_data->sum; hello_msg = my_data->message; ... }
Pthreads: Pasaje de argumentos
int main (int argc, char *argv[]) { ... thrd_data_A[t].thread_id = t; thrd_data_A[t].sum = sum; thrd_data_A[t].message = messages[t]; rc = pthread_create(&threads[t], NULL, ImprimirHola, (void *)
&thrd_data_A[t]); ... }
Otro Ejemplo de Pthreads Estructura de datos para prod/cons
typedef struct { char buf[BSIZE]; pthread_mutex_t lock; pthread_cond_t less; pthread_cond_t more; int nextin; int nextout; int occupied; } buffer_t;
Funciones: void consumer(buffer_t * b); void producer(buffer_t * b); char consume(buffer_t * b); void produce(buffer_t * b, char item);
Otro Ejemplo de Pthreads Variables:
buffer_t *buffer; pthread_mutexattr_t mutex_attr; pthread_condattr_t cond_attr; buffer->occupied = buffer->nextin = buffer->nextout = 0;
Creación de vars de condición y mutex correspondientes:
pthread_mutexattr_init(&mutex_attr); pthread_mutexattr_setpshared(&mutex_attr,
PTHREAD_PROCESS_SHARED); pthread_mutex_init(&buffer->lock, &mutex_attr);
pthread_condattr_init(&cond_attr); pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED); pthread_cond_init(&buffer->less, &cond_attr); pthread_cond_init(&buffer->more, &cond_attr);
Otro Ejemplo de Pthreads void consumer(buffer_t * b){ char item; printf("Consumidor - %d\n", getpid()); while (1) { item = consume(b); if (item == '\0') break; putchar(item); } } void producer(buffer_t * b) { int item; printf(“ Productor - %d\n", getpid()); while (1) { item = getchar(); if (item == EOF) { produce(b, '\0'); break; } else produce(b, (char) item); } }
Prg Principal
if (fork() == 0) {consumer(buffer);
exit(0);} else { producer(buffer);
exit(0);}
Otro Ejemplo de Pthreads char consume(buffer_t * b){ char item;
pthread_mutex_lock(&b->lock);printf("Consume\n");while (b->occupied == 0)
pthread_cond_wait(&b->more, &b->lock);
item = b->buf[b->nextout++];b->nextout %= BSIZE;b->occupied--;
pthread_cond_signal(&b->less);pthread_mutex_unlock(&b->lock);return (item);
}
Otro Ejemplo de Pthreads void produce(buffer_t * b, char item) { pthread_mutex_lock(&b->lock);
printf("Produce\n");while (b->occupied == BSIZE)
pthread_cond_wait(&b->less, &b->lock); b->buf[b->nextin++] = item;
b->nextin %= BSIZE;b->occupied++;
pthread_cond_signal(&b->more);pthread_mutex_unlock(&b->lock);
}