Está en la página 1de 41

Resumen ltimas clases

Herramientas de sincronizacin: - Lock - Semforos Se pueden obtener a partir de las otras. - Monitores - Mensajes Problemas clsicos: - Productor/Consumidor - Filsofos comensales - Lectores/Escritores Errores: - Data race - Deadlock - Hambruna Divesas Implementaciones: - Linux Threads Posix - Windows NT (estndar) - Java 1.4 y Java 1.5

arquitectura de un sistema operativo


jfuentes@ubiobio.cl

Joel Fuentes

Otoo 2011

Temario
ESTRUCTURA DEL COMPUTADOR Busy-Waiting Interrupciones Canales Modo dual ESPACIOS DE DIRECCIONES VIRTUALES ARQUITECTURA DEL S.O. Identificador de proceso Descriptor de proceso Estados de un proceso Cambio de contexto Tajada de tiempo y rfaga de CPU SCHEDULING DE PROCESOS FCFS SJF y SJF con prioridad Round Robin EJEMPLO DE ARQUITECTURA - NSYSTEM

Estructura del Computador


El hardware que ve el Sistema Operativo: Espacio de direcciones reales:
0 2Gb

Obs: consideraciones para sistemas de 32bits


4Gb

DRAM

VRAM (AGP)

ROM (BIOS)

Espacio de E/S:
0 64Kb

Dispositivos generales

Se accesa mediante instrucciones: in / out Mecanismos de E/S: Busy Waiting Interrupciones Canales DMA

Busy-waiting
Este mecanismo ocupa el 100% de la CPU. Ejemplo:
#define N 512 for (;;) { char buff[N]; read(buff, N); El truco procesar(buff, N); }

est en programar este read.

ctrl

data

0xfff0 Implementacin de la funcin read()


char *p_ctrl = 0xfff0; esta direccin es solo un ejemplo! char *p_data = p_ctrl + 1; el byte sgte. void read(char *pb, int n) { while (n--) { While (*p_ctrl & MASK == 0) ; B-W *pb++ = *p_data; } }

hexadecimal

dos bytes

Caratersticas: En un procesador moderno se puede hacer 10 millones de consultas/seg 10 Mb/seg como velocidad de transferencia. (Tasa de transferencia)

Interrupciones (+ busy-waiting)
Se indica al dispositivo que interrumpa el programa en ejecucin Se comanda el dispositivo para realizar la operacin de E/S El programa se dedica a otras actividades (S.O. procesos) Cuando se completa la operacin de E/S se invoca una rutina de atencin, la que realiza la transferencia (en forma transparente para el programa interrumpido).

Implementacin con interrupciones


int nb = 0; n bytes char pb2[N]; 2 buffer de 512 bytes int tot; siempre es 512 bytes a leer void rutinaAtencion() { if (*p_ctrl & MASK == 0) return; while (*p_ctrl & MASK != 0) { pb2[nb++] = *p_data; if (nb == tot) { inhibirIntDisp(); return; } } }

void read(char* pb, int n){ if (nb == 0) activarIntDisp(); while (nb < n) ; bcopy(pb, pb2, n); nb = 0; tot = n; activarIntDisp(); }

Localizacin de la rutina de atencin


Polling: Se consultan todos los dispositivos Vector de interrupciones: se utiliza una tabla Hardware o Software
IRQ1 IRQ2 IRQ3 . . .

Manejo de error en memoria Manejo de error en disco Manejo de error divisin por cero

Evaluacin: 1 procesador moderno ejecuta 10 milln de interrupciones/seg (como mximo) 10MB/seg (tasa de transferencia)

Canales (+ interrupciones)
La diferencia con las interrupciones es que: Con interrupciones: Cuando ocurre la interrupcin los datos estn en el dispositivo (buffer) y hay que transferirlos a la memoria por la CPU, lo que toma tiempo. En el Canal: cuando ocurre la interrupcin los datos ya estn en memoria. Cuando se produce la interrupcin la informacin ya est en memoria porque el canal la transfiri. 100MB/seg (tasa de transferencia)

Modo Dual
Modo Sistema: Todas las instrucciones son vlidas, tiene acceso a todo el hardware, cdigo kernel. En este modo se ejecuta el S.O. Modo Usuario: Permite ejecutar un subconjunto de las instrucciones y tiene acceso limitado al hardware. Instrucciones prohibidas: E/S, proteccin de memoria, etc. En este modo se ejecutan los programas de usuario. Servicios del S.O. mediante llamadas al sistema. Para pasar de un modo a otro: interrupciones software (ejemplo: trap) o interrupciones hardware (divisin por cero, dispositivos de E/S).

Espacio de direcciones virtuales


Para un proceso (pesado):
0
CODIGO DATOS

2Gb
PILA SISTEMA (Ncleo)

4Gb

Direccin virtual. La MMU se encarga de traducir la direccin virtual en real

Las direcciones virtuales se traducen a direcciones reales en la MMU. Cada proceso posee su propio espacio de direcciones. Permite asegurar que un proceso no interfiera con otro.

Espacio de direcciones virtuales


Caractersticas: No hay vector de interrupciones en esta rea No hay dispositivos en esta rea Cdigo read/only (slo lectura) El rea de datos se puede hacer crecer invocando un servicio llamado sbrk (Sbrake es una llamada al sistema) La pila crece automticamente: si la pila se desborda se produce automticamente una interrupcin que hace crecer la pila y luego se retorna el proceso donde qued. Cronmetro regresivo (o timer): Para implementar tajadas de tiempo UNIX tambin permite timers virtuales que se pueden programar, pero en realidad slo existe 1 solo timer fsico.

Arquitectura del SO
fopen, fread, fwrite, malloc, free

aplicacin API

Ncleo
API
drivers Sist. Arch.

open, read, write, sbrk, fork, exec, exit Estructuras del ncleo: Descriptores de proceso, archivos abiertos, colas de procesos, recursos pedidos, etc.

API: Application Program Interface

Arquitectura del SO
Identificador de proceso: es la manera de identificar a los procesos ente s. Fuera del ncleo. Ej: PID en Unix/Linux Descriptor de proceso: es la estructura de datos que representa a un proceso dentro del ncleo. Almacena: estado del proceso, registros (virtuales), informacin de scheduling, recursos asignados, contabilidad, etc.).
/*DESCRIPTOR DE NSYSTEM*/ typedef struct Task { int status; /* READY, ZOMBIE,WAIT_TASK,WAIT_REPLY,WAIT_SEND,*/ char *taskname; SP sp; /*tope de la pila*/ SP stack; /*base de la pila*/ struct Task *nextTask; void *queue /*para nExitTask y nWaitTask*/ int rc; struct Task *wait_task; /* nsend, nReceive,nReply*/ struct queue * send-queue; union {void * mesg; int rc;} send; int wake_timer; int in_wait_squeue }*nTask;

Estados de un Proceso
Tpicamente un proceso puede pasar por distintos estados mientras existe: En creacin: El ncleo est obteniendo los recursos que necesita el proceso para correr (memoria o disco) Corriendo: El proceso est en posesin del procesador, el que ejecuta sus instrucciones. Esperando: el proceso espera que se lea un sector del disco, que llegue un mensaje de otro proceso, que transcurra un intervalo de tiempo, que termine otro proceso, etc. Listo: El proceso est activo pero no est en posesin del procesador. Terminado: El proceso termin su ejecucin pero sigue existiendo para que otros procesos puedan determinar que termin. Colas de Sheduling: Cuando un proceso espera, permanece en estas colas. Estas pueden ser FIFO o colas de prioridades

Estados de una tarea de nSystem


NSYSTEM tambin cuenta con distintos estados definidos para sus tareas, los ms importantes son:

READY: elegible por el planificador o corriendo. ZOMBIE: la tarea llam nExitTask y espera nWaitTask. WAIT-REPLY: la tarea hizo nSend y espera nReply. WAIT-SEND: La tarea hizo nReceive y espera nSend. WAIT-READ: La tarea est bloqueada en un read. WAIT-WRITE: la tarea est bloqueada en un write. Entre otros

Cambio de Contexto
Consiste en el traspaso de la CPU de un proceso a otro. Esto involucra ciertas acciones: 1. Resguardar los registros 2. Contabilizar uso de los recursos (NSystem no tiene contabilizacin) 3. Cambiar el espacio de direcciones virtuales. (esto es lo ms caro en el costo final del cambio de contexto). 4. Restaurar registros del proceso receptor de la CPU.

Tajada de tiempo y Rfaga de CPU


Tajada de tiempo: rango de tiempo asignado por el kernel a un proceso para que ejecute sus instrucciones. En un sistema multiprogramado, el kernel, asigna seguidamente tajadas a cada proceso que se ejecuta (entremezclando sus tajadas) de manera que todos avancen en paralelo. Rfaga de CPU (CPU Burst): secuencia de instrucciones ejecutadas sin pasar a modo de espera. Al final de una rfaga siempre hay que hacer un cambio de contexto.

Scheduling de Procesos
Es la labor fundamental del ncleo, se puede traducir como Planificacin de procesos. El objetivo de la planificacin de procesos es determinar el siguiente proceso a ejecutar (al que se le otorga la CPU). Existen 3 tipo de planificacin: De corto plazo: ejecucin de procesos por el kernel De mediano plazo: relacionado con la tcnica de memoria virtual De largo plazo: usada para programar ejecucin de procesos como por ejemplo: administrador de impresin, recolector de basura, etc. En este momento nos interesa la planificacin de corto plazo, los algoritmos ms comunes son: FCFS SJF Round Robin

Scheduling de Procesos: FCFS


Significa First Come First Served La idea es minimizar los cambios de contexto Es Non-Premptive La rfaga se atiende de principio a fin sin cambio de contexto El orden de atencin es FIFO Existe un parmetro que permite mostrar cuan mala es esta estrategia y se llama Tiempo de despacho Tiempo de despacho (nueva definicin): tiempo comprendido entre que el proceso pasa de modo READY hasta que pasa a un modo de espera.

Scheduling de Procesos
24
A
A,B,C

3
B

3
C

T. Despacho =

24 + 27 + 30 3 = 27

Ahora en otro orden:

3
B
B,C,A

3
C

24
A

T. Despacho = =

3 + 6 + 30 3 13 Bastante mejor!

Ventajas: simple de implementar (con una cola FIFO) Desventajas: No sirve para procesos interactivos No se distribuye bien la carga entre procesos intensivos en CPU y aquellos intensivos en E/S.

Scheduling de Procesos: SJF


Significa Shortest Job First El trabajo ms corto primero Minimiza el tiempo de despacho Atiende primero a los procesos que se espera que tengan rfagas cortas. Ejemplo: Proceso A B C D Duracin rfaga 5 2 20 1

Se ejecutan en este orden segn SJF: D, B, A, C

Problema: No sabemos cunto durar la rfaga de cada proceso

Scheduling de Procesos: SFJ


Cmo estimar la rfaga? Predictor: Tiempos conocidos:
p n+1 : Asociado al proceso p : Queremos estimar la rfaga siguiente. Hemos ejecutado las rfagas 1 hasta n y conocemos sus tiempos. : indica cunto tiempo le damos a la ltima rfaga

Simplificado queda:

Este debe ser un clculo muy simple porque el scheduler debe ocupar lo menos posible la CPU.

Scheduling de Procesos: SFJ


La estrategia SJF es preemptive, posibles casos: Cambio de contexto cuando llega un proceso con predictor menor. Cambio de contexto cuando se excede el predictor para el proceso sgte.

SJF con prioridades


Se entrega la CPU al proceso con mayor prioridad SJF es un caso particular de prioridades (prioridad = Desventaja: hambruna Variante: Aging (es un parche) Cada cierto tiempo se incrementa temporalmente la prioridad de los procesos READY )

Scheduling de Procesos: Round Robin


El scheduler asigna tajadas de tiempo fijo de 10 a 100 milisegundos. Los procesos se organizan en forma circular:

A D C
Esta estrategia minimiza el tiempo de respuesta. En este caso, el tiempo transcurre desde que se inicia una interaccin hasta que aparece el primer resultado (parcial).

Scheduling de Procesos: Round Robin


Implementacin: cola FIFO (es muy simple) El problema es cmo establecer el tamao de la tajada. tamao de la tajada? Es ideal tener tajadas finas, as el tiempo de respuesta es ms corto pero los cambios de contexto aumentan (como costo adicional). El 80% de las rfagas duran menos de una tajada

Arquitectura de nSystem
Mltiples tareas en 1 solo proceso Unix Multiplexar el tiempo de ese proceso Se necesita: Cronmetro regresivo Seales ( interrupciones) E/S no bloqueante
Aplicacin multitarea

E/S nio.c

semforos nSem.c

Mensajes nMsg.c

Tarea nProcess.c

Ubicacin de los fuentes:


ResumeNextReadyTask()

$NSYSTEM/src NSYSTEM
SetAlarm nDep.c

START_CRITICAL() END_CRITICAL() Open read write select

setitimer

sigaction

UNIX

Arquitectura de nSystem
Cmo se realiza un cambio de contexto en NSYSTEM?
Descriptor de la tarea Pila de la tarea Descriptor de la tarea Pila de la tarea

nMain SP
La funcin Q se ejecuta actualmente

P Q

8Kb de pila

nMain SP
Si la tarea pasa a modo de espera, sin que Q termine de ejecutar su cdigo

P Q
PC + Reg activacin

Se utiliza la funcin: void ChangeContext(nTask sale, nTask entra); (19 instrucciones assembler en nstack-i386.s)

Scheduling de nSystem
NSYSTEM utiliza su propia estrategia de planificacin de procesos y se llama: PLCFS o Preemptive Last Come First Served. Funciona as: Las rfagas se atienden en orden LIFO La tarea que llega, recibe la CPU de inmediato La tarea perdedora se coloca en primer lugar en la cola READY Cada t milisegundos se suspende la tarea en ejecucin y se lleva al final de la cola.
llega

Tn T0 Fin tajada

T0

T1

T2

T3

sale

ready queue

Scheduling de nSystem
CPU
llega

Tn T0 Fin tajada

T0

T1

T2

T3

sale

ready queue

1) llega Tn 2) sale T0

Tn

T0

T1

T2

T3

T1

T2

T3

3) fin tajada

T1

T2

T3

T0

Scheduling de nSystem
Implementacin: Variables globales
nTask current_task; Queue ready_queue; int current_slice; /*tarea actual en el procesador*/ /*cola de procesos listos*/ /*duracin de la taja de tiempo*/

Funciones para cambio de contexto por fin de tajada:


void Resume() { /*para no escribir ResumeNextReadytask()*/ nTask esta = current_task; nTask prox = GetTask(ready_queue); current_task = prox; ChangeContext(esta, prox); } current_task = esta;

void VtimerHandler() { setAlarm(VIRTUALTIMER, current_slice, VtimerHandler); PutTask(ready_queue, current_task); Resume(); }

Ejercicio
Implementar el mecanismo de semforos presente en nSystem: nSem nMakeSem(int n); void nWaitSem(nSem s); void nSignalSem(nSem s);
typedef struct { int c; queue q; } *nSem; void nWaitSem(nSem s) { START_CRITICAL(); if (s->c > 0) s->c--; else { current_task->status= WAIT_SEM; PutTask(s->q, current_task); Resume(); } END_CRITICAL(); } void nSignalSem(nSem s) { START_CRITICAL(); if (EmptyQueue(s->q)) s->c++; else { nTask w= GetTask(s->q); w->status= READY; PushTask(ready_queue, current_task); PushTask(ready_queue, w); Resume(); } END_CRITICAL(); }

Manejo del cronmetro del Sistema


En Unix/Linux se manejan dos tipos de alarmas o cronmetros: Alarma de tiempo real: Tiene asociado un contador o temporizador que se decrementa en tiempo real. Cuando el temporizador llega a 0 el ncleo enva al proceso una seal SIGALRM. Alarma de tiempo virtual: Tiene asociado un temporizador que se decrementa cuando el proceso se est ejecutando en modo usuario (tiempo virtual). Cuando el temporizador llega a 0 el ncleo enva al proceso una seal SIGVTALRM. Una elevada resolucin de una alarma de tiempo real no implica una alta precisin. Supngase que un usuario solicita que se le enve una alarma de tiempo real despus de 60 ms. Cuando el tiempo expira, el ncleo enva la seal SIGALRM al proceso. Sin embargo, ste no se percatar de ella y tratar la seal hasta que no sea planificado de nuevo. Esto podra introducir un retardo substancial dependiendo de la prioridad de planificacin del proceso receptor y de la carga del sistema.

Manejo del cronmetro del Sistema


Por el contrario, la precisin de las alarmas de tiempo virtual no sufren del problema descrito para las alarmas de tiempo real, puesto que funcionan solo cuando el proceso est en ejecucin.

P1
nSystem

P2 P3
t1 t2
Fin de tajada de tiempo Unix

t1 termina su
tajada de tiempo

nSystem utiliza el cronmetro virtual para controlar sus tajadas de tiempo, es decir, el scheduler de corto plazo.

Manejo del cronmetro del Sistema


Existen diversas llamadas al sistema que permiten a los usuarios la configuracin de alarmas: en el UNIX System V, la llamada al sistema alarm permite solicitar una alarma de tiempo real, especificando el tiempo en milisegundos. Ejemplo: alarm( SIGALRM, 5 ); en el UNIX BSD, la llamada al sistema setitimer permite al proceso solicitar cualquier tipo de alarma y especificar el intervalo en microsegundos. Ejemplo: setitimer(ITIMER_REAL, &time, NULL); Un proceso solo puede tener una alarma pendiente, para anular una alarma, basta hacer una llamada de alarma con parmetro cero. Se pueden usar simultneamente los cronmetros real y virtual.

Implementacin de nSleep
La instruccin sleep(int ms) de unix permite a un proceso pesado dormir la cantidad de milisegundos indicada en ms. nSleep() de nSystem es similar, con la diferencia que funciona en un ambiente concurrente y es invocada por procesos livianos. Veamos el siguiente ejemplo de uso para nSleep(10)

a)

t1

t2

b)

t1
nSleep(10)

t2

t3

nSleep(10)

10 ms

nSleep(10)

10 ms

10 ms
Seal que indica que se vencieron los siguientes 10 ms

Seal que indica que se vencieron los primeros 10 ms

nSleep() necesita un cronmetro de tiempo real.

Implementacin de nSleep
El cdigo para implementar nSleep() es el siguiente:
void nSeelp(int delay) { START_CRITICAL(); current_task->status= WAIT_SLEEP; ProgramTask(delay); /*Programa la tarea para que se despierte en delay ms*/ Resume(); END_CRITICAL(); }

void ProgramTask(int timeout) { if (timeout>0) { /*si es mayor a cero*/ int curr_time= nGetTime(); /*obtenemos el tiempo actual*/ int wake_time= curr_time + timeout; /*calculamos el tiempo para despertarla*/ if (EmptySqueue(wait_squeue) || /*si la primera tarea debe despertarse*/ wake_time - GetNextTimeSqueue(wait_squeue)<0) /*despues de la actual*/ SetAlarm(REALTIMER, wake_time - curr_time, RtimerHandler); /*prog. timer*/ /*se usa una cola de prioridad, menor tiempo -> mejor prioridad*/ PutTaskSqueue(wait_squeue, current_task, wake_time); } else { /*si timeout es menor a cero, solo se encola en ready_queue nuevamente*/ current_task->status= READY; PushTask(ready_queue, current_task); } }

Implementacin de nSleep
La funcin RTimerHandler() es la encargada de manejar la seal cuando se cumple el tiempo.
void RTimerHandler() { int curr_time= nGetTime(); /* Despertamos todas las tareas con wake_time<=curr_time */ while (! EmptySqueue(wait_squeue) && GetNextTimeSqueue(wait_squeue)<=curr_time) { nTask task= GetTaskSqueue(wait_squeue); /* Ahora la tarea que dorma vuelve a estar READY */ task->status= READY; PushTask(ready_queue, task); } /* Preparamos la prxima interrupcin (seal)*/ SetAlarm(REALTIMER, EmptySqueue(wait_squeue)? 0 : GetNextTimeSqueue(wait_squeue)-curr_time, RtimerHandler); } Cuando se ejecute RTimerHandler() la tarea que est primera en la cola de prioridad provoc la alarma y por ende hay que despertarla. Sin embargo, el sistema puede haber sufrido retrasos y ahora pudieran haber varias tareas que hay que despertar

void CancelTask(nTask task) { DeleteTaskSqueue(wait_squeue, task); }

Ejercicio: Semforos con Timeout


Implemente la primitiva de sincronizacin, para nSystem, llamada Super Semforo. Los prototipos de las funciones son los siguientes: nSuperSem nMakeSuperSem(int n); Crea un super semforo con n tickets void nDestroySuperSem(nSuperSem s); Destruye el semforo, debe indicar si quedan tareas en espera de este semforo. int nWaitSuperSem(nSuperSem s, int timeout); Pide un ticket con un mximo de tiempo de espera. Retorna 1 si obtuvo el ticket y 0 sino. void nSignalSuperSem(nSuperSem s); Aporta un ticket al semforo.

E/S en nSystem
Nn int fd; int rc; fd= nOpen(archivo, flag); rc= nRead(fd, buff, n); rc= nWrite(fd, buff, n); nClose(fd); Problema con nRead()

t1

t2

t3

read() de unix Se bloquea el proceso pesado completo, es decir, t1, t2 y t3

read()

E/S en nSystem
Implementacin de nRead() Se deben colocar los descriptores (fd) en modo no bloqueante, para esto se utiliza la llamada al sistema fcntl de unix. rc = read(fd) Entrega -1 y la variable errno ser igual a la constante EAGAIN EAGAIN significa que el proceso se iba a bloquear.
int nRead(int fd, char *buf, int nbyte) { int rc; START_CRITICAL(); rc= read(fd, buf, nbyte); /* Intentamos leer */ while (rc<0 && errno==EAGAIN) { /* No hay nada disponible */ AddWaitingTask(fd, current_task); /* registrar el descriptor*/ current_task->status= WAIT_READ; ResumeNextReadyTask(); /* Pasamos a la proxima que este ready */ rc= read(fd, buf, nbyte); /* Ahora si que deberia funcionar */ } END_CRITICAL(); return rc; }

E/S en nSystem
static void SigioHandler() { int fd; fd_set readfds, writefds; FD_ZERO(&readfds); FD_ZERO(&writefds); /* Vemos que descriptores tienen asociada E/S pendiente */ for (fd=0; fd<maxsize_pending; fd++) { nTask task= pending_tasks[fd]; if (task!=NULL) /* Hay una tarea pendiente para este descriptor */ if (task->status==WAIT_READ) FD_SET(fd, &readfds); else if (task->status==WAIT_WRITE) FD_SET(fd, &writefds); else nFatalError("SigioHandler","Bug!\n"); } select(maxsize_pending, &readfds, &writefds, NULL, &zero_timeval); /* Vemos para que descriptores se ha resuelto la E/S pendiente */ for (fd=0; fd<maxsize_pending; fd++) { nTask task= pending_tasks[fd]; if (task!=NULL && (FD_ISSET(fd, &readfds) || FD_ISSET(fd, &writefds))) { task->status= READY; PushTask(ready_queue, task); pending_tasks[fd]=NULL; /* Se resolvio ese descriptor */ } } SetHandler(SIGIO, SigioHandler); }

También podría gustarte