Sistemas Operativos - Universidad Tecnológica Nacional

Anuncio
Sistemas Operativos
Universidad Tecnológica Nacional - FRBA
Técnicas Digitales III
Autor: Alejandro Furfaro
1
Introducción
1
1
Sistema Operativo ¿Que es?
Es un programa de control que se ocupa de:
2
2
2
2
1
Administrar los recursos de la computradora.
Administrar la ejecución de los diferentes programas en muchos casos
pueden ser de diferentes usuarios.
Facilitar la tarea del programador permitiendole acceso a los recursos de
manera independiente del hardware.
Proveer servicios a los programas de aplicación a través de un conjunto de
llamadas standard.
Estas acciones se resuelven a través de una implementación que puede
representarse en capas:
Aplicaciones
Programador de Aplicaciones
Utilidades / Servicios
Sistema Operativo
Programador de Sistemas
Hardware
Autor: Alejandro Furfaro
2
Clasificación de los Sistemas
Operativos
1 Sistemas
Real Time:
2Se
utilizan para sistemas de control industriales, centrales de
conmutación, instrumentación científica.
2Por lo general tienen una muy pobre capacidad de interfaz con el
usuario, no tienen utilitarios.
2Su fortaleza consiste en administrar los recursos de la computadora, de
modo de ejecutar una operación en particular en la misma cantidad de
tiempo cada vez que ocurre el evento que la dispara. Concepto evendriven.
2En el tipo de aplicaciones que resuelven estos sistemas operativo, si una
parte se mueve mas rápido solo porque los recursos están disponibles
puede generar resultados tan catastróficos como si no se mueve porque
el recurso está ocupado.
2Ejemplos de implementaciones
QNX
i RT-Linux
i
Autor: Alejandro Furfaro
3
Clasificación de los Sistemas
Operativos
1 Monotarea
- Monousuario
Están preparados para ejecutar solo una tarea a la vez. no puede
ejecutar mas de una en forma concurrente.
2 Interfaz para un solo usuario, (una sola sesión de trabajo).
2 Transfiere el control de la máquina a la aplicación que va a
ejecutarse, y solo interviene a demanda de ésta mediante alguna
llamada a los servicios de su kernel, o cuando la aplicación
finaliza y devuelve el control.
2 El viejo MS-DOS (sucesor del mas viejo aún CPM/86), es el mas
difundido de este tipo de sistemas.
2 Un ejemplo muchísimo mas actual, útil, y eficiente de este tipo de
sistemas es el Palm OS que corre en las computadoras de mano
Palm Pilot. Aquí no hay programas residentes y se tiene un
sistema operativo con una interfaz de usuario muy cómoda que
permite ejecutar aplicaciones de a una por vez.
2
Autor: Alejandro Furfaro
4
Clasificación de los Sistemas
Operativos
1 Multitarea
2
2
2
2
Monousuario
Hoy en día es habitual utilizar estos sistemas operativos en las PC de
escritorio.
Interfaz para un solo usuario, pero pueden mantener en memoria
múltiples aplicaciones en forma estable y dentro de un entorno de
protección (algunos con mas suerte que otros...)
Es habitual descargar correo de Internet o bajar un archivo extenso
durante minutos mientras se trabaja en la redacción de un documento, o
en la escritura de un programa de aplicación, y hasta se chequea el
estado de una unidad de disco , y se realiza un backup de información,
todo a la vez.
Ejemplos habituales de este tipo de sistemas.
i
i
i
i
i
i
Windows XP,
NT Workstation,
2000 Workstation,
OS/2,
Machintosh,
Linux o cualquier UNIX instalado como Workstation
Autor: Alejandro Furfaro
5
Clasificación de los Sistemas
Operativos
1 Multiusuario
2
2
2
2
2
Esta es la forma mas avanzada de los sistemas operativos, y curiosamente
la que primó en los sistemas pioneros como UNIX.
La falta de capacidad del hardware de por entonces (1969) hizo que se
implementasen versiones mas simplificadas para usuarios individuales.
Aquí la interfaz de usuario soporta múltiples sesiones. Esto por extensión
implica que tiene capacidades multitarea, ya que con solo ejecutarse un
proceso por usuario se tiene mas de una tarea en ejecución en la memoria
del sistema.
Estos sistemas son los mas poderosos y normalmente los mas eficientes:
MVS, para los mainframes, UNIX (o cualquiera de sus versiones free como
LINUX, o free BSD, por ejemplo) son los mejores exponentes de este tipo de
sistemas.
Microsoft tiene versiones denominadas Server de Windows XP 2000, y una
evolución de 2000, denominada 2003 que soporta al procesador Itanium.
Autor: Alejandro Furfaro
6
Funciones de un Sistema Operativo
1 Gestión del procesador
2 Gestión del tiempo de procesamiento para cada tarea (scheduling de
procesos).
1 Gestión de la Memoria.
2 Asignación de memoria RAM para las aplicaciones aplicando
criterios basados en la MMU del procesador.
2 Gestión de la Memoria Virtual
2 Gestión de la memoria cache
1 Gestión de los dispositivos de E/S.
2 Acceso al hardware de manera transparente para las aplicaciones.
2 Manejo de la concurrencia de acceso en sistemas multiusuario o
multitarea especialmente
Autor: Alejandro Furfaro
7
Funciones de un Sistema Operativo
1 Gestión del storage
2 (File Systems en los medios masivos de almacenamiento: discos
rígidos, CD-ROMs, DVDs).
1 Interfaz para las Aplicaciones.
2 Colección de llamadas para ejecutarse desde los programas de
aplicación para acceder a servicios brindados pro código del sistema
operativo. Se las conoce como System Calls.
2 En los multitarea se manejan mediante este subsistema, los
diferentes niveles de privilegio que posea el Sistema Operativo (y
que dependen del procesador utilizado en el sistema)
1 Interfaz para los usuarios.
2 Manejo de interfaces sencillas para usuarios no expertos
GUI
i Texto
i Combinación de ambas
i
Autor: Alejandro Furfaro
8
Modelo derivado de las funciones
Pr
oc
es
os
Aplicaciones de usuario
Interfaz de aplicaciones
(API o System Call)
G
es
tió
n
de
Capa de interfaz para
acceso a los servicios
del S.O. Por parte de las
aplicaciones
Hardware
M
em
or
ia
Bu
de ffer
Fi
E/ s
le
S
M Sy
an st
ag em
er
Ge
Scheduler
st
ió
n
de
Se
rv
ic
io
s
De
de
Dr vi
E/
iv ce
S
er
s
Programas de Aplicación
y Utilitarios
Ejecutan en el menor
nivel de privilegio
KERNEL
Hardware
(lo que golpeamos a
causa de los
estándares de calidad
de algunos S.O.’s ....)
Autor: Alejandro Furfaro
9
Linux: Introducción
1
1
1
Sistema Operativo Unix-like
Basado en POSIX (Portable OS based on UNIX)
Kernel monolítico (programa único +módulos)
2
1
1
Diseñado bajo el concepto Lightweight Processes (LWP)
Nonpreemptive
2
2
1
1
1
1
1
Opuesto a los Sistemas MicroKernel que reinaron en los 70’s.
No puede intercalar arbitrariamente flujos de ejecución mientras está en
modo privilegiado.
Solaris 2.x y Mac 3.0 son full preemptive
Soporta SMP (Symetric MultiProcessing)
Soporta varios File Systems (IBM AIX, SGI Irix, FAT32, etc)
Puede ser muy pequeño. Se puede ajustar a un floppy 3”1/2
Es libre. Podemos intslarlo y modificar su código sin otra limitación que
nuestro hardware.
Versiones. Se representan con tres números separados por puntos. Ej:
2.4.18, o 2.5.22. El primero es la Versión. El segundo indica si es un
kernel estable (par) o en desarrollo (impar). El tercero es el release.
Autor: Alejandro Furfaro
10
El Kernel
1
1
Es el principal programa del SO
Actualmente soportado por las siguientes arquitecturas:
2
2
2
2
2
2
2
2
1
Aprovecha las capaciades del hardware
2
2
1
ARM (ARM based Computers)
Alpha (Compaq)
Intel (ia32 e ia64-Itanium)
Familia 68K (Motorola)
MIPS (Silicon Graphics)
Power PC
Sparc y Ultra Sparc (32 y 64 bits Sun Microsystems)
S390 (IBM)
Maneja el acceso a los recursos hardware específicos. A través de
Device Drivers.
Provee servicios de acceso al hardware a los programas de usuario.
Es reentrante
2
Múltiples procesos acceden al kernel de manera simultánea.
Autor: Alejandro Furfaro
11
El Kernel
1 Maneja niveles de Protección
2 Ejecución en modo Kernel.
2 Ejecución en modo User.
2 Maneja Stacks separados.
Proceso 3
SystemCall
Call
System
Handler
Handler
Autor: Alejandro Furfaro
Scheduler
Scheduler
Proceso 4
Requerimiento a un
driver / Interrupción
desde un dispositivo
página de memoria
no presente)
Fallo de Página
Modo
Kernel
(Accede a una
Interrupción de
timer
Modo
Usuario
Servicio del
Sistema
Proceso 1
Proceso
2
Exception
Exception
Handler
Handler
Device
Device
Driver
Driver
12
Manejo de Memoria
Modelo:
Dirección Lógica
Segmento:Desplazamiento
Unidad
Unidad de
de
Segmentación
Segmentación
Dirección Lineal
Unidad
Unidad de
de
Paginación
Paginación
Dirección Física
Autor: Alejandro Furfaro
13
Manejo de Memoria: Tabla GDT
Segmentación: Basada en Modelo FLAT
1 Descriptores en GDT
2
2
2
Advanced
Power
Management
2
1
Los cuatro segmentos tienen:
2
2
2
2
2
2
2
Autor: Alejandro Furfaro
Kernel Code Segment (KCS)
Kernel Data Segment (KDS)
User Code Segment (UCS)
User Data Segment (UDS)
Base = 0x00000000
Limit = 0xfffff
G (granularity flag) = 1, para expresar el tamaño
del segmento en paginas de 1024 bytes.
S (system flag) = 1, para segmentos de código
normales.
Type = 0xA, para segmentos de código que se
puedan leer y ejecutar, o 0x2 para segmentos de
datos de lectura / escritura.
DPL (Descriptor Privilege Level): 0 para Modo
Kernel (KCS y KDS), o 3 para Modo Usuario (UCS
y UDS)
D/B (32-bit address flag) = 1. Direcciones con
14
offset de 32 bits
Manejo de Memoria : Tabla GDT
1
Descriptores de Sistema
2
Task State Segment Descriptor (TSSD): Uno por cada procesador.
Limite =0xEB (236 bytes).
i S = 1, DPL = 00, Tipo = 9 u 11 (TSS de 32 bits Available / Busy )
i Dirección Base
init_tss
i
CPU#0_TSSD
CPU#1_TSSD
CPU#n_TSSD
i
2
Se aplian las TSS de cada CPU en un array llamado init_tss
LDT Descriptor: uno genérico compartido por todos los procesos. El
kernel de Linux no usa LDT.
Contiene un descriptor Null.
i Dirección base: Se almacena en la default_ldt.
i Límite 7
i Los procesos pueden crear su propia LDT mediante una función especial
del kernel: modify_ldt( ).
i
Autor: Alejandro Furfaro
VOLVER
15
Manejo de Memoria
1 Paginación:
2 Paginas de tamaño fijo (4 u 8 KB)
2 Definiciones:
PAGE = Es el rango de direcciones lineales mapeados dentro de esa
página, junto con los datos contendidos por dichas direcciones (En la
jerga, “data chunk”)
i Page Frame = Es el área de memoria que contiene una página, por eso
también se la puede encontrar bajo el nombre de phisical page, o page
container
i
2
Paging Unit:
i
2
Extended Paging:
i
2
A partir del pentium se tiene la posibilidad de definir páginas de 4Mbytes.
Three-level paging
i
1
Convierte direcciones lineales en físicas
Procesadores de 64 bit.
Ubicación de las páginas del Kernel
Autor: Alejandro Furfaro
16
Paginación
Paginación
Extendida
Paginación
Paginación en
tres niveles
Autor: Alejandro Furfaro
17
Modelo Kernel/Proceso
1
Proceso: Instancia de un programa en ejecución, o un
contexto de ejecución.
2
2
2
1
1
Tienen un espacio de direccionamiento determinado (direcciones de
memoria que tienen permitidas para acceder)
Normalmente trabajan en modo User.
Cuando requieren servicios del kernel, switchean a modo kernel. Una
vez resuelto el requerimiento regresan a modo User
El kernel hace que cada proceso “vea” una CPU dedicada.
Es un administrador de procesos
Existe un grupo de programas privilegiado llamados “kernel
threads”.
2
2
2
2
Corren en modo Kernel en el espacio de direccionamiento del kernel.
No interactúan con el usuario.
No tienen terminal asociada.
Se crean durante el startup y mueren en el shutdown
Autor: Alejandro Furfaro
18
Procesos
1 El
kernel debe saber para cada proceso:
2 Su
prioridad
2 Su estado
2 Su espacio de direcciones asignado
2 Sus archivos abiertos y en acceso
1 Descriptores
de Proceso, estructura task_struct, VER
2 El
kernel define un array de estas estructuras
denominado task_array.
1 Parentezco
Autor: Alejandro Furfaro
entre procesos.
19
Descriptor de Procesos
1
state
flags
nedd_resched
counter
nice
next_task
prev_task
tty_struct
Lista de tty’s
asociadas al
proceso
run_list
p_optr
p_pptr
……….
1
fs_struct
Directorio
actual
tty
1
files_struct
Punteros a
file
descriptors
thread
fs
files
mMm
sigmask_lock
sig
…….
Autor: Alejandro Furfaro
mm_struct
Punteros a
descriptores
de áreas de
memoria
signal_struct
Tiene por objeto darle al
Sistema Operativo la
visión clara de que está
haciendo el proceso.
Definido en la
declaración de
task_struct VER
Dada la complejidad de
esta estructura algunos
campos son referencias
a otras estructuras
como la tabla de file
descriptors del proceso
Señales
recibidas
20
Identificando un proceso
1 Cada
proceso tiene un Descriptor que lo define
unívocamente.
1 Los punteros a los descriptores de proceso sirven
para identificarlos. Son Números de 32 bits
1 Los UNIX identifican a los procesos con un Process
ID (PID). Los PID van desde 0 a 32767.
1 El Process ID corresponde al campo pid en el
descriptor de proceso (task_struct)
task_struct
Autor: Alejandro Furfaro
21
Estados de un proceso
1 Corresponden
al campo state de task_struct.
Valores posibles (flags)
2 TASK_RUNNING
2 TASK_INTERRUPTIBLE
2 TASK_UNINTERRUPTIBLE
2 TASK_STOPPED
2 TASK_ZOMBIE
*/ Definidos en usr/src/linux/sched.h */
#define TASK_RUNNING
0
#define TASK_INTERRUPTIBLE
1
#define TASK_UNINTERRUPTIBLE 2
#define TASK_ZOMBIE
4
#define TASK_STOPPED
8
1 Para
setear el estado de un proceso el kernel usa
las macros set_task_state o set_current_state 22
Autor: Alejandro Furfaro
Descriptor de Proceso: Alocando
memoria
1 En
union task_union
{
struct task_struct task;
unsigned long stack[2048];
};
Autor: Alejandro Furfaro
Kernel Mode, los
procesos usan un Stack
del Segmento de Datos del
Kernel.
1 El uso de este stack no es
intensivo.
1 Los stacks expanden hacia
la base de memoria (el
registro esp se
decrementa)
1 Conociendo el registro esp
se deduce el comienzo del
Descriptor de Proceso
23
La Macro current
1
1
Sirve para que el kernel pueda ubicar el inicio del Descriptor
de Proceso.
El código es:
movl $0xffffe000, %ecx
andl %esp, %ecx
movl %ecx, p
1
Tiene dos complicaciones.
2
2
Cuando hay poca memoria RAM
Cuando se trabaja con sistemas SMP
Se usa caché de 16 task_union
1 free_task_struct (),
() libera los 8K de memoria usados por el
proceso en curso y lo guarda en el caché a menos que esté
full
1 alloc_task_struct(),
() aloja los 8 K en memoria y si hay dos
páginas seguidas en el caché los cachea
1
Autor: Alejandro Furfaro
24
Lista de Procesos
1 Task
array: Lista doblemente enlazada de punteros
a estructuras de tipo task_struct
1 La cantidad de elementos se guarda en la variable
N_TASKS. El campo pid es el índice de este arreglo.
1 Los campos prev_task y next task de los
descriptores de procesos (task_struct),
task_struct vinculan
los elementos.
1 El primer elemento es el puntero a task_struct del
proceso 0 llamado swapper.
Autor: Alejandro Furfaro
25
Implementación de listas doblemente
enlazadas en Linux
1 Linux
utiliza numerosas listas doblemente
enlazadas.
1 Buscando un estilo de programación homogéneo
se define la siguiente estructura genérica:
struct list_head {
struct list_head *next, *prev;
};
1 La
misma se encuentra en el archivo /usr/src/linux[version]/includes/linux/list.h
List_head
List_head
List_head
next
prev
next
prev
next
prev
Autor: Alejandro Furfaro
26
Runqueue
1 Por
una cuestión de eficiencia,el kernel mantiene
una lista separada de los procesos que están en
estado TASK_RUNNING.
1 La variable nr_running mantiene la cantidad de
procesos en este estado.
1 La lista está encabezada por init_task (descriptor
de proceso del proceso 0 o swapper )
1 El campo run_list de task_struct es una estructura
list_head para implementar esta lista.
1 Funciones:
2 add_to_runqueue():
()
Inserta un proceso a la lista
2 del_from_runqueue():
() remueve un proceso de la lista
2 move_first_runqueue():
() Mueve un proceso al principio
de la lista
2 move_last_runqueue():
() Mueve un proceso al final de la
27
Autor:
Alejandro Furfaro
lista
Parentesco entre procesos
1 En
el descriptor de procesos se dispone de los
siguientes campos para reflejar parentesco
2p_opptr
(original parent)
2p_pptr (parent)
2p_cptr (child)
2p_ysptr (younger sibling)
2p_osptr (older sibling)
Autor: Alejandro Furfaro
28
Creación de procesos
1 Cada
vez que un proceso crea a otro, le transfiere
sus recursos. Pero no se duplican
1 Copy on write. El kernel detecta el acceso a
modificar un recurso por parte del child y en ese
momento le crea una copia propia.
1 Lightweight processes. Comparten las estructuras
del kernel, y el espacio de direcciones en modo
User.
Autor: Alejandro Furfaro
29
Creación de procesos: fork ()
1 Se
emplean diferentes system calls para crear
procesos. La mas utilizada es fork ().
()
Proceso
principal
Descriptor Proceso
principal
If (!fork())
Internal de
fork (kernel)
Retorna PID del
proceso creado
FALSE
Proceso
hijo
Descriptor Proceso
child
Retorna 0
TRUE
Proceso en
memoria física
Una
Una misma
misma copia
copia física
física del
del código
código yy los
los
datos
datos en
en memoria
memoria apuntada
apuntada por
por dos
dos
descriptores
descriptores de
de proceso
proceso diferentes.
diferentes. Una
Una
copia
=
Dos
procesos.
(Lightweight
Process)
copia = Dos procesos. (Lightweight Process)
Autor: Alejandro Furfaro
30
Creación de procesos: vfork ()
1 La
system call vfork () crea un child que hace suyo
el espacio completo de direcciones del proceso
padre, obligándolo a esperar su finalización si
requiere acceso a un objeto compartido.
1 El espacio de direcciones del proceso se compone
de:
2 El
código ejecutable del programa
2 El área de datos inicializados del programa.
2 El área de datos no inicilizados el programa
2 El stack inicial del programa (el stack de Modo User)
2 El código ejecutable y los datos de las librerías
compartidas necesarias.
2 El heap (la memoria que el programa puede requerir
dinámicamente)
Autor: Alejandro Furfaro
31
clone ()
1
1
System Call propia e LINUX.
__clone (fn, arg, flags, child_stack)
2
2
2
fn es la función que ejecutará el proceso child, que finaliza cuando
dicha función ejecute return ().
arg: Puntero a la lista de argumentos de fn.
flags: cuatro bytes. El menos significativo es el número de la señal
que el child va a enviar al padre cuando termine (default SIGCHILD).
Los otros codifican flags:
CLONE_VM: comparte descriptores de memoria y las tablas de páginas
i CLONE_FS: comparte la tabla que identifica el file system
i CLONE_FILES: comparte la tabla de descriptores de archivos abiertos
i CLONE_SIGHAND: comparte la tabla de handlers de señal
i CLONE_PID: comparte el PID (solo si el parent tiene PID 0 y en entorno
uniprocesador
i CLONE_PTRACE: si el parent es traceado por ptrace(), el hijo también
i CLONE_VFORK:
i
2
child_stack: indica el stack de Modo USER que se le asignará al
esp del child. Si es 0, corresponde al stack de modo USER del
parent
Autor: Alejandro Furfaro
32
Flags del proceso
1 Corresponden
al campo flags en el descriptor de
proceso.
#define PF_ALIGNWARN
0x00000001
#define PF_STARTING
#define PF_EXITING
#define PF_FORKNOEXEC
#define PF_SUPERPRIV
#define PF_DUMPCORE
#define PF_SIGNALED
#define PF_MEMALLOC
#define PF_MEMDIE
#define PF_FREE_PAGES
#define PF_NOIO
#define PF_FSTRANS
#define PF_USEDFPU
/* Ptrace flags */
#define PT_PTRACED
#define PT_TRACESYS
#define PT_DTRACE
#define PT_TRACESYSGOOD
#define PT_PTRACE_CAP
Autor: Alejandro Furfaro
0x00000002
0x00000004
0x00000040
0x00000100
0x00000200
0x00000400
0x00000800
0x00001000
0x00002000
0x00004000
0x00008000
0x00100000
0x00000001
0x00000002
0x00000004
0x00000008
0x00000010
/* Print alignment warning msgs */
/* Not implemented yet, only for 486*/
/* being created */
/* getting shut down */
/* forked but didn't exec */
/* used super-user privileges */
/* dumped core */
/* killed by a signal */
/* Allocating memory */
/* Killed for out-of-memory */
/* per process page freeing */
/* avoid generating further I/O */
/* inside a filesystem transaction */
/* task used FPU this quantum (SMP) */
/* delayed trace (used on m68k, i386) */
/* ptracer can follow suid-exec */
33
Límite de direcciones de un proceso
1 El
campo addr_limit de task_struct es una
estuctura del tipo
typedef struct {
unsigned long seg;
} mm_segment_t;
1 contiene:
2 El
valor PAGE_OFFSET para procesos normales
2 0xFFFFFFFF para kernel threads.
1 El
kernel puede cambiar dinámicamente el valor de
addr_limit.seg mediante las macros get_fs y
set_fs.
set_fs Esto le permite al kernel invocar
directamente system calls a rutinas de servicio y
pasarles las direcciones en el segmento de datos
del kernel (KDS_desc, CPL = 00)
Autor: Alejandro Furfaro
34
Dominios de ejecución
1
Linux puede ejecutar programas nativos de otros S.O.
2
2
1
En el caso de sistemas No POSIX, emplea emuladores que traducen
“on the fly” las llamadas de la aplicación al kernel de su S.O. Nativo,
a llamadas POSIX para el kernel de Linux (Ej. Wine o DOSemu)
Si el sistema es POSIX, en general no hay problemas ya que todos
trabajan con el mismo API.
Para especificar su S.O. Nativo, un proceso necesita definir
Personality Operating system
su dominio de ejecución
PER_LINUX
Standard execution domain
2
2
Setea el campo personality de la
estructura exec_domain de su
descriptor de proceso (task_struct)
system call personality ().
Autor: Alejandro Furfaro
PER_SVR4
PER_SVR3
PER_SCOSVR3
PER_OSR5
PER_WYSEV386
PER_ISCR4
PER_BSD
PER_SUNOS
PER_XENIX
PER_IRIX32
PER_IRIXN32
PER_IRIX64
PER_RISCOS
PER_SOLARIS
PER_UW7
System V Release 4
System V Release 3
SCO Unix Version 3.2
SCO OpenServer Release 5
Unix System V/386 Release 3.2.1
Interactive Unix
BSD Unix
SunOS
Xenix
SGI Irix-5 32 bit
SGI Irix-6 32 bit
SGI Irix-6 64 bit
RISC OS
Sun's Solaris
Caldera's UnixWare 7
35
Scheduling de procesos
1 Linux
divide el tiempo de la CPU en períodos (o
épocas)
1 En cada época de la CPU, Linux (como UNIX)
asigna un quantum de tiempo a cada proceso ->
time slicing
1 La duración del quantum es critica en la
performance
1 Tres clases de procesos
2 Interactivos
2 Batch
2 Real
Time
1 Preempción.
Se maneja con el campo
need_resched del descriptor de proceso
Autor: Alejandro Furfaro
36
Políticas de Scheduling / Time
Sharing
1
1
Linux programa al timer tick de modo de generar una
interrupción (tick) cada 10mseg. aproximadamente.
Un proceso tiene asignado un tiempo de ejecución llamado
quantum, que es múltiplo entero de un tick.
2
2
El valor de ticks asignado a un proceso se almacena en el campo
counter del descriptor de proceso (task_struct).
Cuando expira el quantum, se suspende la ejecución del proceso. La
rutina que llama el kernel desde el handler del timer tick para esta
función es update_ process_times( ) cuyo código es
if (current->pid) {
--current->counter;
if (current->counter <= 0) {
current->counter = 0;
current->need_resched = 1;
}
}
2
2
Si counter < 0 => need_resched se pone a 1.
Antes de volver a Modo User (para lo cual ejecutará la función
ret_from_sys_call( ))se
chequea si need_resched = 1 se invoca la
)
función schedule ( ) para pasar al siguiente proceso en la lista.
Autor: Alejandro Furfaro
37
Políticas de Scheduling / Time
Sharing
1 Otros
campos de task_struct relacionados con
laspolíticas de scheduling son:
2 policy.
policy
Define la clase de scheduling:
i SCHED_FIFO.
Proceso Real Time First-In First-Out. Cuando le
asigna CPU, el scheduler lo deja en su posición actual en la
run_queue a menos que exista otro proceso real time de mayor
prioridad en estado TASK_RUNNING.
i SCHED_RR.Proceso Real Time Round Robin. Cuando le asigna
CPU el scheduler lo envía al fondo de la run_queue. Es mas justo
que el anterior para procesos de igual prioridad.
i SCHED_OTHER. Proceso común de tiempo compartido.
2 rt_priority.
rt_priority
Es la prioridad de un proceso real time (1 a
99).
2 nice.
nice Determina la longitud de un quantum al inicio de un
nuevo período de la CPU (o época). Vale de –20 a +19
(de mayor a menor proridad. EN generalk un proceso se
lanza con un valor 0, en este campo.
Autor: Alejandro Furfaro
38
Políticas de Scheduling / Time
Sharing
1 Otros
campos de task_struct relacionados con
laspolíticas de scheduling son:
2 cpus_allowed.Bit
cpus_allowed
mask que especifica las CPUs
presentes en el sistema sobre las que el proceso está
habilitado para ejecutar. Para arquitecturas IA-32 el
máximo número de CPUs es 32, de modo que la máscara
cabe en un int.
2 cpus_runnable.
cpus_runnable Bit mask que especifica cual de las
CPUs del sistema es la que está ejecutando el proceso.
Si el proceso no está siendo ejecutado por ninguna CPU
del sistema todos los bits de esta máscara están en 1.De
otro modo están en 0 todos los bits excepto el
correspondiente a la CPU que está ejecutando el
proceso. Mediante una AND entre este campo y
cpus_allowed el kernel puede determinar si un proceso
puede ser schedulado sobre una CPU determinada.
2 processor.
processor Indica que CPU está ejecutamndo el proceso
o en su defecto cual fue la última en ejecutarlo.
39
Autor: Alejandro Furfaro
Process Preemption
1 Los
procesos en Linux son interrumpibles
(preempted).
1 Cuando un proceso entra en estado
TASK_RUNNING, el kernel chequea su prioridad y
la compara con el corriente. Si su prioridad es
mayor el proceso actual es interrumpido
(preempted).
1 Cuando a causa de una interrupción se debe
despertar a un proceso (ponerlo TASK_RUNNING)
y su prioridad es mayor que la del proceso en
curso, el kernel setea el bit current>need_resched y por lo tanto antes de salir de la
interrupción se llamará a la función schedule ( )
para pasar al nuevo proceso.
40
Autor: Alejandro Furfaro
Temporización y scheduler System
Calls
1 Temporizacion
2 time
()
2 ctime ()
2 ftime ()
2 gettimeofday ()
1 Manejo
de scheduler
2 nice
()
2 renice ()
2 getpriority ()
2 setpriority ()
Autor: Alejandro Furfaro
41
Trace de procesos
Cuando se invocan las system call clone( ),
) fork( ),
) o vfork(
), el kernel llama a la función do_fork( ).
)
1 do_fork () ejecuta numerosas acciones para crear un
proceso. Algunas dependen de los flags que se le pasen
como argumentos a las funciones primitivas:
1 Si no se seteó el flag CLONE_PTRACE,
1
2
2
1
do_fork () pone a ‘0’ el campo ptrace en el descriptor de proceso
(task_struct) del proceso child.
Este campo almacena algunos pocos flags utilizados cuando un
proceso está siendo “traceado” por otro. El child no deberá
“tracearse” aún cuando lo esté siendo el proceso actual.
La función ret_from_fork( ) chequea el valor del campo
ptrace del descriptor de proceso actual (offset 24 de
task_struct). If Si el campo no es nulo , “se tracea” la system
call fork( ),
) vfork( ),
) o clone( ),
) invocandose a la función
syscall_trace( ) para notificar al proceso de debugging.
Autor: Alejandro Furfaro
42
Global Kernel Locks
1 Han
ido decrementando su uso a medida que
evolucionó el kernel desde las versiones 2.0 a 2.4
1 Actualmente se usan para sibncronizar accesos al
File system y para evitar condiciones de carreras
entre procesos.
1 Consisten en un spin lock llamado kernel_flag
1 Los utilizan handlers de interrupción y excepción y
procesos botton half.
1 Cuando un proceso requiere un kernel lock invoca
la system call lock_kernel (),
() y para liberarlo se
invoca unlock_kernel (),
() que incrementan y
decrementan el campo lock_depth del descriptor
de proceso
Autor: Alejandro Furfaro
43
Conmutación de Procesos
1 Es responsbilidad del scheduler (sched.c) e incluye:
2 Contexto de Hardware
i Directorio de Páginas para cambiar al nuevo espacio de
direcciones
i Stacks de Modo User y Modo Kernel, mas los Registros propios
de los procesadores IA-32
2 Registros adicionales que al igual que en el procesador de Intel hay
que manejarlo en forma manual, por falta de soporte en el hardware
i Registros de FPU
i Registros
2
de control y Debug
Utiliza una macro llamada switch_to() en lugar de utilizar un jump far
al descriptor del TSS
h void switch_to (struct task_struct *prev, struct task_struct *next,
struct task_struct *last)
Autor: Alejandro Furfaro
44
Conmutación de Procesos
1 Linux
mantiene una única TSS por cada CPU. VER
1 A pesar del no uso de jmp far para conmutar no
puede prescindir de al menos un TSS por cada
CPU:
2 Al
aumentar el nivel de privilegio de una tarea, el
procesador busca en el TSS actual (cuyo selector
contiene el registro TR), los valores de SS y ESP
correspondientes al mayor nivel de privilegio.
2 Para acceder a E/S desde una tarea cuyo CPL no sea el
adecuado debe consultarse el IO BitMap del TSS de la
tarea.
1 Al
usar un único TSS por CPU, Linux debe
actualizarle determinados campos en cada process
switch.
Autor: Alejandro Furfaro
45
Conmutación de Procesos
1 El
contexto de hardware de cada tarea se
almacena en una estructura del tipo thread en
task_struct.
task_struct VER
1 Esta estructura puede ser tomada por cualquier
CPU presente en el sistema ya que contiene los
datos que de guardarse en la TSS no podrían ser
tomados por otra CPU.
1 Observaciones:
2 Solo
guarda los registros de propósito general
estrictamente necesarios. El resto va al stack
2 Se almacena el estado de la FPU, y debug registers que
no son contemplados en el TSS
2 Se mantiene el bitmap de E/S del proceso en esta
estructura
Autor: Alejandro Furfaro
46
Conmutación de Procesos:
macro switch_to()
1
Se invoca desde schedule () mediante la linea
switch_to (prev, next, prev)
1
Se ejecuta el siguiente código
movl
movl
movl
prev,%eax
next,%edx
%eax,%ebx
;eax = prev
;edx = next
;ebx = eax = prev
push
%esi ; apila en pila de Modo Kernel del proceso prev
push
%edi ; los registros esi,edi, y ebp
push
%ebp
;la estructura thread ocupa el offset 608 dentro de task_struct
movl
%esp, 616(%eax)
; salva esp en prev->thread.esp
movl
616(%edx), %esp
; carga esp con next->thread.esp
movl
$1f, 612(%eax)
; guarda ret addr en prev->thread.eip
pushl 612(%edx)
; guarda ret addr en next->thread.eip
jmp
__switch_to
Autor: Alejandro Furfaro
47
Conmutación de Procesos:
rutina __ switch_to
1 Ejecuta
los siguientes pasos:
2 unlazy_fpu
(prev) ;Si cambiaron, salva los registros de
la FP, MMX, y XMM.
2 Init_tss [smp_precessor_id ( ) ].esp0 = next ->thread.esp0
i Smp_processor_id
( ) devuelve el índice a la CPU que está
ejecutando elñ proceso
2 Salva
en la estructura thread los registros FS y GS (El
kernel no los usa, pero las aplicaciones pueden usarlos.
movl %fs, 620 (%esi) ;esi apunta a prev -> thread
movl %gs,624 (%esi)
2 Carga
los nuevos valores de fs y gs.
movl 12 (%ebx),%fs ;ebx apunta a next -> thread
movl 16 (%ebx),%gs
Autor: Alejandro Furfaro
48
Conmutación de Procesos:
rutina __ switch_to
2
Salva los valores de los debug registers, si el proceso al que se va a
activar los había utilizado.
if (next->thread.debugreg[7]){
loaddebug(&next->thread, 0);
loaddebug(&next->thread, 1);
loaddebug(&next->thread, 2);
loaddebug(&next->thread, 3);
/* no 4 and 5 */
loaddebug(&next->thread, 6);
loaddebug(&next->thread, 7);
}
2
Salva en el TSS de la CPU que corresponda los valores de IO
BitMap, si prev o next tienen permisos customizados de E/S.
if (next->thread.ioperm) {
memcpy(init_tss[smp_processor_id( )].io_bitmap, next-> thread.io_bitmap,128));
init_tss[smp_processor_id( )].bitmap = 104;
} else if (prev->thread.ioperm)
init_tss[smp_processor_id( )].bitmap = 0x8000;
Autor: Alejandro Furfaro
49
Conmutación de Procesos:
rutina __ switch_to
2__switch_to
fue llamada mediante un jmp. Pero
antes se guardó en la pila la dirección de retorno.
popl %ebp
popl %edi
popl %esi
2Finalmente
copia el contenido de %ebx en la
variable prev
mov %ebx,prev
Autor: Alejandro Furfaro
50
Kernel threads
1
Son hilos de ejecución del kernel que corren
permanentemente en modo kernel para cumplir funciones
específicas
2
2
2
2
1
1
1
swapping out de una página no utilizada
atender conexiones de red
flush de los caches de disco
etc.
Solo un kernel thread puede crear un kernel thread
Ejecutan solo una función específica del sistema (los
procesos Modo USER pueden ejecutar varias syscall)
swapper o Process 0: es el primer kernel thread, creado en
el arranque por la función start_kernel().
Autor: Alejandro Furfaro
51
Interrupciones y Excepciones
1 Interrupciones
2Sincronicas:
Excepciones (se producen una vez
completada la instrucción en curso).
2Asincrónicas: Interrupciones de Hardware.
1 Vectores
en Linux:
20-31
excepciones y NMI
232-47 IRQ's
2El resto para Int's soft, Linux usa la 128 (0x80)
(system calls, cunado un proceso user la ejecuta,
se pasa a modo kernel).
1 Interrupt
Handling ≠ Process Switching
Autor: Alejandro Furfaro
52
IDT
1 Asocia
interrupciones y excepciones con sus
respectivos handlers.
1 Es reinicializada luego del POST, de acuerdo a lo
establecido en la dispositiva anterior
1 Linux NO usa rutinas del BIOS!. Son de modo Real.
Las reemplazan funcionalmente los Device Drivers
1 Se inicializa antes que el kernel habilite las
interrupcoines!!!
1 Puede contener tres tipos de descriptores:
2 Task
Gate (Linux NO los usa!!!)
2 Interrupt Gate (para atender interrupciones)
2 Trap Gate (para atender excepciones)
1 Linux
diferencia de intel los nombres...
Autor: Alejandro Furfaro
53
IDT
1 Terminologia
Linux:
1 Interrupt Gate:
2 Solo
para modo Kernel
2 Son las interrupt gates de intel con DPL=0.
1 System
Gate: es la trap gate de Intel.
23
(int3)
2 4 (into)
2 5 (bound)
2 128 (system call) (equiv a int 21 en DOS)
2 Se ejecutan en modo user.
1 Trap
Gate: es una trap gate Intel pero solo
accesible en modo kernel.
Autor: Alejandro Furfaro
54
Handlers de Excepciones del
procesador
#
Exception
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Divide error
Debug
NMI
Breakpoint
Overflow
Bounds check
Invalid opcode
Device not available
Double fault
Coprocessor segment overrun
Invalid TSS
Segment not present
Stack exception
General protection
Page Fault
Intel reserved
Floating-point error
Alignment check
Machine check
SIMD floating point
Autor: Alejandro Furfaro
Exception handler
divide_error( )
debug( )
nmi( )
int3( )
overflow( )
bounds( )
invalid_op( )
device_not_available( )
double_fault( )
coprocessor_segment_overrun( )
invalid_tss( )
segment_not_present( )
stack_segment( )
general_protection( )
page_fault( )
None
coprocessor_error( )
alignment_check( )
machine_check( )
simd_coprocessor_error( )
Signal
SIGFPE
SIGTRAP
None
SIGTRAP
SIGSEGV
SIGSEGV
SIGILL
SIGSEGV
SIGSEGV
SIGFPE
SIGSEGV
SIGBUS
SIGBUS
SIGSEGV
SIGSEGV
None
SIGFPE
SIGBUS
None
SIGFPE
55
Manejo de las excepciones
1 Linux
asume las excepciones como condiciones de
error, y las trata en consecuencia
1 Cuando el procesador genera una excepción, el
kernel toma el control y envía al proceso que
causante de la excepción una señal (Ver tabla de la
diapositiva anterior).
2 Ante
una división por 0, el kernel envía SIGFPE al
proceso.
2 El proceso maneja la señal o deja al handler default del
kernel. En el caso de SIGFPE, el default es abort.
1 Los
handlers de Excepción en general proceden a:
2 Salvar
la mayoría de los registros en el stack de Modo
Kernel (esta parte se codifica en assembly).
2 Manejar la excepción mediante una función de alto nivel
escrita en C.
2 Salir mediante la función ret_from_exception( ).
Autor: Alejandro Furfaro
56
Excepciones de manejo de recursos
1 Cuando
una excepción obedece a mecanismos del
procesador para el manejo de recursos, el kernel
debe determinar si responde a un error de la
aplicación o si en cambio es una excepción habitual
en el acceso a un recurso.
1 Analizamos el comportamiento (global) de la
Acceso de acuerdo
excepción Page Fault.
Excepción 14
La Excepción ocurrió
en Modo Kernel
Bug del Kernel !!!
Mata al proceso
Excepción en
Modo User por
violación de los
permisos del
área de
memoria.
con los permisos del
área de memoria.
Acceso Legal. Aloja
el Page Frame
Acceso Ilegal. Envía
SIGSEGV
Autor: Alejandro Furfaro
57
Zoom en la Excepción 14
Autor: Alejandro Furfaro
58
Manejo de Interrupciones
IRQ
INT
0
32
Timer
1
33
Keyboard
2 IRQ_Sharing
2
34
PIC cascading
3
35
Second serial port
2 IRQ
4
36
First serial port
6
38
Floppy disk
8
40
System clock
10
42
Network interface
11
43
USB port, sound card
12
44
PS/2 mouse
13
45
Mathematical coprocessor
14
46
EIDE disk controller's first chain
15
47
EIDE disk controller's second chain
1 Flexibilidad
en el
Handler de Interrupción
Dynamic Allocation
Device
Device
Device Device
Device Device
#2
#n
#1
#n
#2
#1
PIC
PIC
IRQn_Interupt
IRQn_Interupt (( ))
do_IRQ
do_IRQ (n)
(n)
Hardware
Autor: Alejandro Furfaro
Software
ISR1
ISR1 (( ))
Hardware Device
El
ElS.O.
S.O.Debe
Debeser
sercapaz
capazde
de
compartir
una
misma
IRQ
compartir una misma IRQ
entre
entrediferentes
diferentesISR’s
ISR’s
(Interrupt
Service
(Interrupt ServiceHandlers)
Handlers)
ISR2
ISR2 (( ))
59
Manejo de Interrupciones
1El
proceso interrumpido está TASK_RUNNING.
1Tiene
1La
asignado un quantum para su ejecución.
Interupción no puede superar ese quantum
2Acciones
críticas. Se resuelven en el handler con las
interrupciones deshabilitadas
2Acciones
No críticas. Se resuelven en el handler con las
interrupciones habilitadas
2Acciones
No críticas diferibles. Se ejecutan en algún
momento oportuno fuera del handler de interrupción
Autor: Alejandro Furfaro
60
Manejo de las Interrupciones en
Linux
Rango
Uso
0-19 (0x0-0x13)
Nonmaskable interrupts and exceptions
20-31 (0x14-0x1f)
Reservado por Intel
32-127 (0x20-0x7f)
External interrupts (IRQs)
128 (0x80)
Programmed exception for system calls
129-238 (0x81-0xee)
External interrupts (IRQs)
239 (0xef)
Local APIC timer interrupt
240-250 (0xf0-0xfa)
Reserved by Linux for future use
251-255 (0xfb-0xff)
Interprocessor interrupts
Vectores
Vectores de
de Interrupción
Interrupción en
en Linux
Linux
Autor: Alejandro Furfaro
61
softirqs, tasklets, y bottom halves
1 Son
métodos del kernel (en particular kernel
threads) para resolver tareas no críticas diferibles.
2 Tasklets
ejecutan sobre softirqs
2 Botton halves ejecutan por medio de tasklets
Función
Diferible
Allocación
DInámica
Concurrencia
No
Pueden ejecutar en forma concurrente en
diferentes CPU’s aún si son del mismo tipo.
Tasklet
Si
Pueden ejecutar en forma concurrente en
diferentes CPU’s Tasklets de diferente tipo, no
así tasklets del mismo tipo.
Bottom half
No
Bottom halves no pueden ejecutar
concurrentemente en diferentes CPU’s.
Softirq
Autor: Alejandro Furfaro
62
softirq’s
1
1
1
Corren como kernel threads estáticos.
Cada thread corresponde a una softirq y su tipo es el
definido en la tabla siguiente.
El kernel lleva la cuenta de las softirq’s pendientes
Chequea por softirq’s pendientes en varios puntos:
2
2
2
2
2
Cuando se rehabilitan las softirq’s mediante la macro
local_bh_enable
Cuando se finaliza un handler de interrupción
Cuando termina el handler de interrupción del timer o del local timer
en sistemas SMP
Cuando se despierta un kernel thread que maneja una softirq
Cuando se recibe un paquete en la placa de red.
Softirq
HI_SOFTIRQ
0
NET_TX_SOFTIRQ
1
NET_RX_SOFTIRQ
2
TASKLET_SOFTIRQ
3
Autor: Alejandro Furfaro
Description
Index (priority)
Mayor Prioridad
1
Maneja tasklets y bottom halves de alta
prioridad
Transmite paquetes a las placas de red
Recibe paquetes desde placas de red
Maneja tasklets
63
tasklets
1
1
1
1
Se utilizan para implementar funciones diferibles en Device
Drivers.
Se cargan en forma dinámica (móduos)
Se construyen sobre softirq’s de tipo HI_SOFTIRQ y
TASKLET_SOFTIRQ. (Prioridad única diferencia)
Se manejan mediante una estructura del tipo tasklet_struct
Campo
Descripción
Next
Puntero al próximo descriptor en la lista
State
Estado de la tasklet
Count
Contador de Locks
Func
Puntero a la función de la tasklet
Data
unsigned long que puede ser utilizado por la función tasklet
Autor: Alejandro Furfaro
64
Botton Halves
1 Esencialmente
Bottom half
Peripheral device
es una
TIMER_BH
Timer
tasklet de alta prioridad que TQUEUE_BH Cola de tarea periódica
no puede ejecutarse de
DIGI_BH
DigiBoard PC/Xe
SERIAL_BH
Serial port
manera concurrente con
RISCOM8_BH
RISCom/8
otro bottom half, aún si es SPECIALIX_BH Specialix IO8+
de tipo diferente ni sobre
AURORA_BH
Aurora multiport card (SPARC)
ESP_BH
HaSi ESP serial card
una CPU dkiferente.
SCSI_BH
SCSI interface
1 El spin lock global_bh_lock IMMEDIATE_BH Cola de tarea Immediata
Cyclom-Y serial
se utiliza para asegurar que CYCLADES_BH Cyclades
multiport
CM206_BH
CD-ROM Philips/LMS cm206 disk
a lo sumo se ejecute un
MACSERIAL_BH Power Macintosh's serial port
solo bottom half.
ISICOM_BH
MultiTech's ISI cards
Linux
Linux Botton
Botton Halves
Halves
Autor: Alejandro Furfaro
65
Temporizaciones
1 El
kernel lleva a cabo dos tipos de
temporizaciones:
2 Mantiene
la fecha y hora que retorna a los programas de
aplicación como respuesta a las System Calls time (),
ftime (), y gettimeofday ()
2 Mantiene Timers, es decir, mecanismos que le notifique a
él o a las aplicaciones que ha transcurrido un lapso de
tiempo predeterminado
Autor: Alejandro Furfaro
66
Temporizaciones
1 Hay
2 El
tres relojes de hardware en una PC:
RTC (Motorola 146818).
i Usa
IRQ8, para interrumpir desde 2 hasta 8192Hz.
i Se accede por /sbin/clock
i Actúa sobre el dispositivo /dev/rtc
i Se accede en la address 70h y 71h de E/S
2 Time
Stamp Counter
i Registro
homónimo (TSC) de 64 bits interno al procesador a partir
del Pentium. Cuenta a la velocidad del clock
2 Programable
Interval Timer (8254)
i Usa
IRQ0
i Es programado en el startup para interrumpir a 100 hz
Autor: Alejandro Furfaro
67
Timer Interrupt Handler
1 Actualiza
el tiempo transcurrido desde el startup
1 Actualiza Hora y Fecha
1 Determina cuanto hace que corre el proceso actual
y eventualmente decide si lo “schedula”.
1 Actualiza los time stamps de uso de los recursos
del sistema
1 Chequea los estados de los timers de software en
uso por parte de las aplicaciones
Autor: Alejandro Furfaro
68
Timer Interrupt Handler
1 Tiene
2 Una
dos partes:
en tiempo real
i Actualiza
tres variables
4 Jiffies
-> ticks transcurridos desde el startup (el kernel la inicializa a
0). Roll Over 497 días....
4 Lost_ticks -> cantidad de ticks transcurridos desde la última
actualización de la estructura xtime
4 Lost_ticks_system -> cantidad de ticks transcurridos en Modo Kernel
desde la última actualización de la estructura xtime
2 La
otra diferida (botton half)
i Actualiza
fecha y hora
i Actualiza estadísticas de uso del sistema
i Actualiza el campo Counter de la copia del descriptor del proceso
actual que guarda en la macro current. Si expiro el tiempo
asignado schedula otro proceso
Autor: Alejandro Furfaro
69
System Calls
1
1
1
API: Formato de una llamada para obtener un servicio del
kernel
System Call: requerimiento explícito cursado al kernel para
resolver un servicio.
La inversa no es necesariamente cierta. Algunas API
resuelven directamente en Modo Usuario si pasar a Modo
kernel para resolver el pedido (math.lib por ejemplo).
Modo Usuario
…
func ()
…
func () ¨{
…
int 80h
…
}
Accede a una rutina
Aplicación
Wrapper en la
Invoca
System Call librería standard libc
Autor: Alejandro Furfaro
Modo Kernel
system call:
…
sys_func ()
…
ret_from_sys_call:
…
iret
sys_func () {
…
…
…
}
handler de
System Call
del kernel
rutina de
servicio de la
System Call
70
IPC (Inter Process Communication)
1 Como
hacer que dos o más procesos intercambien
información
1 Sincronización de Objetos.
1 Primero debemos contar con más de un proceso
(fork y exec).
1 Warning: fork () -> poder, poder asociado gralmente
a destruccion!!!
1 Cuidado con esto!
Autor: Alejandro Furfaro
71
IPC, Señales
1 Los
procesos pueden señalizarse entre sí o puede
hacerlo el kernel.
1 Algunas señales no pueden ignorarse, otras
pueden interceptarse y cambiar el handler.
1 Conjunto de SIG signals (kill –l)
1 Comando kill – permite enviar señales desde el
prompt
Autor: Alejandro Furfaro
72
IPC, Señales
#
1
2
3
4
5
6
6
7
8
9
10
11
12
13
14
15
16
Nombre
SIGHUP
SIGINT
SIGQUIT
SIGILL
SIGTRAP
SIGABRT
SIGIOT
SIGBUS
SIGFPE
SIGKILL
SIGUSR1
SIGSEGV
SIGUSR2
SIGPIPE
SIGALRM
SIGTERM
SIGSTKFLT
Acción Default
Terminate
Terminate
Dump
Dump
Dump
Dump
Dump
Dump
Dump
Terminate
Terminate
Dump
Terminate
Terminate
Terminate
Terminate
Terminate
Autor: Alejandro Furfaro
Descripción
POSIX
Se desconectó la terminal asociada al procesoSi
Interrupción desde el teclado
Si
Quit desde el teclado (CTRL+C)
Si
Si
Instrucción ilegal
Breakpoint para debugging
No
Abnormal termination
Si
Equivalente a SIGABRT
No
Bus error
No
Floating-point exception
Si
Fuerza la terminación del proceso
Si
Dispponible para el proceso
Si
Referencia inválida a memoria
Si
Si
Dispponible para el proceso
Escritura en un pipe sin procesos lectores
Si
Real-timer clock
Si
Si
Terminación de un Proceso
Coprocessor stack error
No
73
IPC, Señales
#
17
18
19
20
21
22
23
24
25
26
27
28
29
29
30
31
31
Nombre
SIGCHLD
SIGCONT
SIGSTOP
SIGTSTP
SIGTTIN
SIGTTOU
SIGURG
SIGXCPU
SIGXFSZ
SIGVTALRM
SIGPROF
SIGWINCH
SIGIO
SIGPOLL
SIGPWR
SIGSYS
SIGUNUSED
Acción Default
Ignore
Continue
Stop
Stop
Stop
Stop
Ignore
Dump
Dump
Terminate
Terminate
Ignore
Terminate
Terminate
Terminate
Dump
Dump
Autor: Alejandro Furfaro
Descripción
Proceso Child STOPPED o terminó
Reasume la ejecución, si estaba STOPPED
Detiene al proceso (lo pone STOPPED)
Idem SIGSTOP enviada por la tty (CTRL+Z)
Proceso Background requiere entrada
Proceso Background requiere salida
Condición Urgent en un socket
Límite de tiempo de CPU excedido
Tamaño límite de Archivo excedido
Virtual timer clock
Profile timer clock
Window resizing
Ahora es posible una Operación de I/O
Equivalente a SIGIO
Power supply failure
system call errónea
Equivalente a SIGSYS
POSIX
Si
Si
Si
Si
Si
Si
No
No
No
No
No
No
No
No
No
No
No
74
Campos de task_struct relacionados
con las señales
Type
Name
Description
spinlock_t
sigmask_lock
Protección por Spin Lock para pendientes y
bloqueadas
struct
signal_struct *
sig
Puntero al descriptor de señal del proceso
sigset_t
blocked
Máscara de las señales bloqueadas
struct
sigpending
pending
unsigned long
sas_ss_sp
size_t
sas_ss_size
int (*) (void *)
notifier
void *
notifier_data
Puntero al dato que debe usar la función de
notificación (cambio prevo de la tabla)
sigset_t *
notifier_mask
Máscara de Bits de señales bloqueadas por un
device driver mediante la función de notificación
Autor: Alejandro Furfaro
Estructura de Datos para almacenar las señales
pendientes.
Dirección del stack del handler alternativo de la
señal.
Tamaño del stack del handler alternativo de la
señal.
Puntero a la función usada por un device driver
para bloquear algunas señales del proceso
75
Campos de task_struct relacionados
con las señales
struct signal_struct {
atomic_t
struct k_sigaction
spinlock_t
};
struct sigpending {
count;
action[64];
siglock;
struct sigqueue * head, * tail;
sigset_t signal;
}
struct sigqueue {
struct sigqueue * next;
siginfo_t info;
}
Autor: Alejandro Furfaro
76
Control de las señales
struct
task_struct
struct
sigpending
Head
Tail
Signal
pending
sig
struct
signal_struct
count
Descriptor
de Proceso
action
struct
sigqueue
Head
Next
struct
sigqueue
Head
Next
struct
sigqueue
Head
Next
Info
Info
Info
struct
sigaction
sa_handler
sa_flags
sa_mask
siglock
Descriptor
de Señal
Autor: Alejandro Furfaro
77
IPC, mecanismos
1 Algunas
operaciones con IPC:
2 Pipes
2 Named
Pipes (FIFOS)
2 File Locking
2 Sys V IPC's
i Message
queues
i Semaphores
i Shared Memory
2 Mem.
Mapped Files
2 Sockets
Autor: Alejandro Furfaro
78
“We're back to the times when men where men and
wrote their own device drivers...”
Device Drivers
1 Basicamente
Linus Torvalds
es código que se ejecuta en modo
Kernel.
1 Es la mediación entre los dispositivos hard y los
procesos del sistema o de usuario.
1 Linux puede incluirlo:
2 En
el kernel monolítico (rapido y compacto)
2 Como modulos run time linkeables (flexible pero lento la
primera vez que se usa).
1 Se
tiende cada vez mas a estructura modular.
1 El driver se ocupa de resolver el mecanismo de
acceso al hardware. No se concentra en la política
de manejo de la información, aspecto que queda
para el software de usuario
Autor: Alejandro Furfaro
79
Device Drivers:
inserción en el kernel
Autor: Alejandro Furfaro
80
Device Drivers: Clasificación
1
Char devices
2
2
1
Se acceden como un stream de bytes, tal como si fuesen nodos del
File System. Ej: TTY's (/dev/console). Serial ports (/dev/ttyS0)
A diferencia de los archivos comunes, no nos podemos desplazar
hacia atrás y hacia adelante. Accede a los datos en forma
secuencial.
Block devices
2
2
2
Se acceden en el directorio /dev igual que los char devices.
La dferencia pasa por como el kernel maneja internamente los datos.
Por lo regular es de a bloques (512 o 1024 bytes)
Son dispositivos que pueden hostear un File System. Ej: Discos,
Cintas.
Autor: Alejandro Furfaro
81
Device Drivers: Clasificación
1
Network devices
2
2
1
Controlan las interfaces para transaccionar paquetes de datos en red
contra un equipo remoto, sin conocer en detalle el mapa de
transacciones que conforman esos paquetes.
No siempre son de hardware (loopback por ejemplo) Al no ser un
dispositivo orientado a stream, no es fácilmente mapeable en el /dev
Miscelaneos
2
Algunos autores clasifican en una categoría especial , y diferentes de
las tres básicas a los drivers de los controladores de buses, ya que
son bastante particulares.
PCI
i USB
i SCSI
i
Autor: Alejandro Furfaro
82
Device Drivers: Módulos
1 Escribir
un device driver, es escribir código de
kernel En modo kernel se dispone de un tipo
especial de programa denominado Módulo de
Kernel (kernel module)
1 Una aplicación convencional realiza una tarea única
del principio hasta el fin.
1 Un módulo se registra a si mismo a fin de prestar
servicios a futuro. Su función principal es efímera,
pero queda “instalado” en el sistema
1 ¿impacientes? ..... Bueno ahí va....
#define MODULE
#include <linux/module.h>
int init_module(void) {
printk("<1>¡Hola mundo! \n");
return 0; }
void cleanup_module(void) {
printk("<1>¡Adios mundo cruel!\n");
} Alejandro Furfaro
Autor:
83
Device Drivers: Módulos
1
1
1
¿y la función main??????
No usa. ¿entonces?......
Veamos como se compila y ejecuta (atentos con el
prompt....)
root# gcc -c hello.c
root# insmod ./hello.o
¡Hola mundo!
root# rmmod hello
¡Adios mundo cruel!
root#
1
1
1
Insmod y rmmod, se utilizan para testear nuestro módulo.
Insmod lo instala. Una vez ejecutado quedará registrado
hasta ejecutar rmmod
insmod hace que se ejecute la función init_module ()
(Con Uds.... La “función main” del módulo)
rmmod hace ejecutar la función cleanup_module ().
Autor: Alejandro Furfaro
84
Device Drivers: Módulos
Autor: Alejandro Furfaro
85
Device Drivers: Esquema de llamadas
al sistema
Memoria
User Mode
System Cal
API
open()
write()
close()
Autor: Alejandro Furfaro
Kernel Mode
File_ops
Dev_open()
Dev_write()
Dev_close()
Device
outb()
Ports
86
Char Devices: File Operations (1)
• struct module *owner
Es el primer campo de file_operations
No es en sí mismo una operación
Es un puntero al módulo “dueño” de la estructura.
Se usa para evitar que el módulo sea cargado mientras sus
operaciones están en uso.
– A menudo se lo inicializa sencillamente con la macro THIS_MODULE,
definida en <linux/module.h>.
–
–
–
–
• loff_t (*llseek) (struct file *, loff_t, int);
– El método llseek se usa para cambiar la posición actual de lectura/
escritura en un archivo
– La nueva posición se retorna como un valor positivo
– loff_t es un “long offset” y tiene al menos un ancho de 64 bits aún
en plataformas de 32-bit.
– Si se produce algún error en su ejecución retorna un valor negativo
– Si este puntero se inicializa en NULL en file_operations, seek ()
modificará el contador de posición en la estructura file (de formas
potencialmente impredecibles).
87
Autor: Alejandro Furfaro
Char Devices: File Operations (2)
• ssize_t (*read) (struct file *, char __user *, size_t,
loff_t *);
– Lee datos desde un archivo o device.
– Un puntero NULL en esta posición hace que la system call read ()
sobre este device devuelva -EINVAL (“Invalid argument”).
– Un valor de retorno no negativo representa el número de bytes
leídos
• ssize_t (*aio_read)(struct kiocb *, char __user *,
size_t, loff_t);
− Inicia una lectura asincrónica (puede no completarse antes de
retornar).
− Si es NULL, todas las operaciones serán ejecutadas en forma
sincrónica por read ().
• ssize_t (*write) (struct file *, const char __user *,
size_t, loff_t *);
– Envía datos a un archivo o device.
– Si este puntero es NULL, la system call write () retorna -EINVAL al
programa que la invoca
– Un valor de retorno, no negativo, es el número de bytes escritos. 88
Autor: Alejandro Furfaro
Char Devices: File Operations (3)
• ssize_t (*aio_write)(struct kiocb *, const char __user
*, size_t, loff_t *);
– Inicia una operación de escritura asincrónica sobre el device.
• int (*readdir) (struct file *, void *, filldir_t);
– Se usa para leer directorios. Solo lo usan los file systems. Debe ser
NULL para cualquier device.
• unsigned int (*poll) (struct file *, struct
poll_table_struct *);
– El método poll es el back end de tres system calls: poll (), epoll (),
y select ().
– Se usa para saber si un read () o un write () a uno o mas
descriptores de archivo va a bloquear.
– El método poll () debe retornar una máscara de bits que indica si
son factibles lecturas o escrituras no bloqueantes.
– El kernel con esta información pone un proceso en estado sleeping
hasta que sea posible la operación de E/S.
– Si un driver deja NULL este método, se asume que puede ser leído o
escrito sin bloqueo.
89
Autor: Alejandro Furfaro
Char Devices: File Operations (4)
• int (*ioctl) (struct inode *, struct file *, unsigned
int, unsigned long);
– La system call ioctl () envía comandos device específicos.
– El kernel generalmente procesa ioctl () por medio del método
definido en file_operations.
– Si no hay un method ioctl (), la system call retorna error para
cualquier requerimiento no predefinido (-ENOTTY, “No such ioctl for
device”).
• int (*mmap) (struct file *, struct vm_area_struct *);
– mmap requiere el mapeo de un device de memoria al espacio de
direcciones del proceso.
– Si este método es NULL, la system call mmap () retorna -ENODEV.
• int (*open) (struct inode *, struct file *);
– Como SIEMPRE es la primer operación realizada sobre el archivo o
device, no es necesario declararlo
– Si es NULL, el device siempre se abre, pero no se notifica al driver.
Autor: Alejandro Furfaro
90
Char Devices: File Operations (5)
• int (*flush) (struct file *);
– La operación flush () se invoca cuando un proceso cierra su copia
del file descriptor de un device
– Ejecuta (y espera por) cualquier operación excepcional sobre el
device.
– No confundir con la operación fsync () requerida por un programa.
– flush () se usa en muy pocos drivers: el driver SCSI de cinta lo use,
por ejemplo, para asegurar que todos los datos escritos estén en la
cinta antes de cerrar el dispositivo
– Si es NULL, el kernel simplemente ignora el requerimiento.
• int (*release) (struct inode *, struct file *);
– Se invoca cuando se desea liberar la estructura.
– Igual que open () puede ser NULL.
– release () no se invoca cada vez que un proceso llama a close ().
Si una estructura file se comparte (como resultado de fork () o
dup() ), release () se invoca cuando todas las copias ejecutan
91
close
().Furfaro
Autor:
Alejandro
Char Devices: File Operations (6)
• int (*fsync) (struct file *, struct dentry *, int);
– Es el back end de la system call fsync (), que es llamada por un
programa para flushear cualquier dato pendiente. Si es NULL,
retorna -EINVAL.
• int (*aio_fsync)(struct kiocb *, int);
– Es la versión asincrónica del método fsync.
• int (*fasync) (int, struct file *, int);
– Se usa para notificar al device que cambió su flag FASYNC.
– Puede ser NULL si el driver no soporta notificación asincrónica.
• int (*lock) (struct file *, int, struct file_lock *);
– Se usa para implementar file locking.
– Es indispensable en archivos, pero rara vez se usa en drivers.
Autor: Alejandro Furfaro
92
Char Devices: File Operations (7)
• ssize_t (*readv) (struct file *, const struct iovec *,
unsigned long, loff_t *);
• ssize_t (*writev) (struct file *, const struct iovec
*, unsigned long, loff_t *);
– Implementan operaciones de lectura escritura fragmentada, que
ocasionalmente necesitan involucrar múltiples áreas de memoria
– Estas system calls fuerzan operaciones extra de copia sobre los
datos.
– Si estos punteros se dejan NULL, se llaman en su lugar los métodos
read () y write () (quizá mas de una vez).
• ssize_t (*sendfile)(struct file *, loff_t *, size_t,
read_actor_t, void *);
– Implementa el lado read de la system call sendfile (), que mueve
los datos desde un file descriptor hacia otro con mínima copia
– Se usa por ejemplo en un web server que necesita enviar los
contenidos de un archivo fuera hacia la red.
– Los
device
drivers
Autor:
Alejandro
Furfaro
normalmente la dejan en NULL.
93
Char Devices: File Operations (8)
• ssize_t (*sendpage) (struct file *, struct page *, int,
size_t, loff_t *, int);
– sendpage es la otra mitad de sendfile;
– El kernel la llama para enviar datos al archivo correspondiente, una
página a la vez.
– Los device drivers normalmente no implementan sendpage.
• unsigned long (*get_unmapped_area) (struct file *,
unsigned long, unsigned long, unsigned long, unsigned
long);
– El objetivo de este método es encontrar una ubicación adecuada en
el espacio de direcciones del proceso para mapearla sobre un
segmento de memoria del device.
– Normalmente es el código de manejo de la memoria quien realiza
esta tarea
– Este método permite a los drivers forzar los requerimientos de
alineamiento que pueda tener cualquier device. La mayoría de los
drivers dejan este método NULL.
Autor: Alejandro Furfaro
94
Char Devices: File Operations (9)
• int (*check_flags)(int)
– Permite al módulo chequear los flags que se le pasan en una
llamada fcntl (F_SETFL...).
• int (*dir_notify)(struct file *, unsigned long);
– Se invoca cuando una aplicación usa fcntl () para pedir
modificaciones en un directorio.
– Sólo es útil en file systems
– Los drivers no necesitan implementar dir_notify.
Autor: Alejandro Furfaro
95
Char Devices: File Operations (10)
Es la estructura principal para mapear el sistema de system calls del
sistema operativo sobre el hardware
• Declaradas en <linux/fs.h>
struct file_operations
struct file_operations
midriver_fops = {
midriver_fops =
NULL,
//lseek
{
midriver_read,
.owner = THIS_MODULE,
midriver_write,
.read = scull_read,
NULL,
//readdir
.write = scull_write,
NULL,
//poll
.ioctl = scull_ioctl,
midriver_ioctl,
.open = scull_open,
NULL,
//mmap
.release = scull_release,
midriver_open,
};
NULL,
//flush
midriver_release,
NULL,
//fsync
NULL,
//fasync
NULL,
//check_media_change
NULL,
//revalidate
NULL,
//lock
96
};
Autor: Alejandro Furfaro
•
Otras estructuras del sistema a
considerar: struc file
1 Definida
en <linux/fs.h>
1 Contiene la información lógica de un archivo abierto
con open ().
1 Campos de interés para un char device
2 mode_t f_mode; //Modo en
(FMODE_READ, FMODE_WRITE)
que se abrió el archivo
2 loff_t
f_pos; //Puntero de 64 bits offset dentro del archivo
2 unsigned int f_flags; //O_RDONLY, O_NONBLOCK, O_SYNC.
2 struct file_operations *f_op;
2 void *private_data;
i open
() la carga con NULL antes de llamar al método open propio
del driver.
i Se puede utilizar para guardar datos propios del driver
2 struct
dentry *f_dentry;
Autor: Alejandro
Furfaroentry
i Directory
97
Otras estructuras del sistema a
considerar: struct inode
1 Definida
en <linux/fs.h>
1 Contiene
la información de un nodo del file system
(no de un archivo abierto)
2 Campos
i dev_t
de interés para un char device
i_rdev; //contiene el número de device (32 bits: 12 major
number 20 minor number)
i struct
cdev *i_cdev; //es una estructura del LDM que representa
a un char device. Si el inodo no contiene un char device este
campo es NULL.
2 Para
obtener el major y el minor number a partir de inode
i unsigned
Autor: Alejandro Furfaro
i
int iminor (struct inode *inode);
d i
i
j
(
i
d
*i
d )
98
Device Drivers: Módulos
1 El
kernel de LINUX es concurente, por lo tanto un
driver debe estar escrito con la idea que en un
mismo instante ocurren varias cosas. Debe ser
reentrante.
1 Desde el kernel no tenemos los recursos que
usamos en las aplicaciones:
2 No
se accede a las system call standard
2 No están disponibles los IPCs!!!!
1 Ejemplo.
Para averiguar el proceso que invocó
alguna de las funciones el driver, vamos a
task_struct.....
printk("The process is \"%s\" (pid %i)\n", current->comm, current->pid);
1 Es
decir: Bienvenidos a la cocina del restaurante.
¿se entiende?
Autor: Alejandro Furfaro
99
Device Drivers: Char devices
1
1
Deben existir como filesystem node en /dev
Se crean con un comando especial:
“mknod <nombre> <type> <Mn> <mn>”
1
Numero mayor y menor.
crw-rw-rwcrw------crw------crw-rw-rwcrw-rw-rwcrw------crw------crw-rw-rw-
1
1
1
1
1
1
1
1
1
1
root
root
rubini
root
root
root
root
root
root
root
tty
dialout
dialout
sys
sys
root
1,
10,
4,
4,
4,
7,
7,
1,
3
1
1
64
65
1
129
5
Feb
Feb
Aug
Jun
Aug
Feb
Feb
Feb
23
23
16
30
16
23
23
23
1999
1999
22:22
11:19
00:00
1999
1999
1999
null
psaux
tty1
ttyS0
ttyS1
vcs1
vcsa1
zero
El kernel usa el Major number para despachar la ejecución
del driver correcto en el momento en que se ejecuta la
función open () desde el proceso que lo desea acceder.
El Minor number es usado por el driver. El kernel solo lo
pasa al driver para que este lo utilice si lo necesita.
Autor: Alejandro Furfaro
100
Device Drivers: Hands On! (1)
struct file_operations ser_fops = {
read:
ser_read,
write:
ser_write,
open:
ser_open,
release:
ser_release
};
int init_module()
{
if (register_chrdev(SER_MAYOR, "ser", &ser_fops)){
printk("<1> SER: init_module ha fallado instalando SER
driver...\n");
return -EIO;
} else {
printk("<1> SER: modulo instalado!\n");
return 0;
}
}
Autor: Alejandro Furfaro
101
Device Drivers: Hands On! (2)
void cleanup_module (){
if (ser_busy)
printk("<1> SER: driver ocupado, no se pudo remover....
\n");
else {
if (unregister_chrdev(SER_MAYOR,"ser") != 0)
printk("<1> SER: cleanup_module ha fallado,
no se puede desregistrar SER deiver...\n");
else
printk("<1> SER: modulo desinstalado!\n");
}
}
Autor: Alejandro Furfaro
102
Device Drivers: Hands On! (3)
Método
Open
(1)
static int ser_open(struct inode * inode, struct file * file)
{
int codigo;
unsigned char bitpos = 1;
// verifico minor igual a cero
unsigned int minor = MINOR(inode->i_rdev);
#ifdef SERDEB
printk("<1> SER: abriendo...\n");
#endif
if (minor != 0) return -ENODEV;
// verifico semaforo en verde. Si está siendo usado
if (ser_busy==SER_BUSY) return -EBUSY;//sale por error
ser_busy=SER_BUSY;
// lo marco ocupado
codigo = request_irq (SER_IRQ, ser_irq, SA_INTERRUPT,"ser",
NULL); //pido irq...
if (codigo){
printk ("<1> SER: no se puede utilizar la interrupción
%d\n",SER_IRQ);
return codigo;
Autor: Alejandro Furfaro
103
Device Drivers: Hands On! (4)
Método
Open
(2)
} else {
// habilito mascara de interrupciones en el PIC master
bitpos = ~(bitpos << SER_IRQ);
outb (inb(0x21)&(bitpos),0x21);
outb (0x20, 0x20);
#ifdef SERDEB
printk("<1> SER: IRQ registrada.\n");
#endif
}
//aqui setear la velocidad del puerto también se debería
//guardar la velocidad anterior de la misma forma que la
//mascara original
outb(0x08, SER_MCR);//out2 del MCR
outb(0x01, SER_IER);//habilita interrupciones del 8250 IER
#ifdef SERDEB
printk ("<1> SER: puerto abierto.\n");
#endif
return 0;
}
104
Autor: Alejandro Furfaro
Device Drivers: Hands On! (5)
Método Release
static int ser_release (struct inode *inode, struct file *file)
{
unsigned char bitpos = 1;
#ifdef SERDEB
printk ("<1> SER: release.\n");
#endif
ser_busy=SER_FREE;
free_irq(SER_IRQ,NULL); //error check
outb(0x00, SER_IER); //deshabilita interrupciones en el IER
bitpos = (bitpos << SER_IRQ);
outb (inb(0x21)|(bitpos),0x21); //libera mascara de PIC
outb (0x20, 0x20);
#ifdef SERDEB
printk ("<1> SER: serial cerrado.\n");
#endif
return 0;
}
Autor: Alejandro Furfaro
105
Device Drivers: Hands On! (6)
Petición de IRQ al kernel
1int
request_irq (unsigned int irq, void (*handler)
(int, void *, struct pt_regs *), unsigned long flags,
const char *dev_name, void *dev_id);
2 Retorna 0 o un código negativo de error. (-EBUSY si otro driver
está usando la IRQ pedida por ejemplo).
2 Argumentos
i
i
i
unsigned int irq: Número de la IRQ requerida.
void (*handler) (int, void *, struct pt_regs *): Puntero a la función
que se desea instalar como handler.
unsigned long flags: Máscara de bits relacionada al manejo de
interrupciones.
4
4
i
i
1void
SA_INTERRUPT, Indica que es un ‘‘fast’’ interrupt handler: Se
ejecutará aún con las interupciones deshabilitadas
SA_SHIRQ. Indica que la interrupción puede compartirse entre varios
devices.
const char *dev_name: Nombre del device en /dev. Lo usa en
/proc/interrupts para mostrar el dueño de la IRQ.
void *dev_id: Puntero usado para compartir IRQ’s. Cuando no se
comparte IRQ se lo deja en NULL
free_irq (unsigned int irq, void *dev_id);
Autor: Alejandro Furfaro
106
Device Drivers: Hands On! (7)
Método Read (1)
int ser_busy = SER_FREE;
// pongo una cola de espera
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)
DECLARE_WAIT_QUEUE_HEAD(ser_wait); //cabeza de cola de espera
#else
struct wait_queue *ser_wait_q;
ser_wait_q=NULL;
#endif
int readready = 0;
static void ser_irq(int irq,void *dev_id,struct pt_regs *regs){
char testvalue;
//despierta al que esta esperando la int SER_IRQ
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)
wake_up_interruptible(&ser_wait);
#else
wake_up_interruptible(&ser_wait_q);
#endif
testvalue=inb(SER_IIR); // ack de ints en 8250 leyendo IIR
} Autor: Alejandro Furfaro
107
Device Drivers: Hands On! (8)
Método Read (2)
static ssize_t ser_read (struct file *file, char *buf, size_t
count, loff_t *nose){
char testvalue;
if (count != 1) return -EINVAL; // debe leer de a uno
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)
interruptible_sleep_on(&ser_wait);
#else
interruptible_sleep_on(ser_wait_q);
// espero interrupción
#endif
testvalue=inb(SER_IN); //lee lo que llego
__copy_to_user(buf,&testvalue,count); //envío dato al user
return count;
}
Autor: Alejandro Furfaro
108
Device Drivers: Hands On! (9)
Colas de Espera
1 La
lista runqueue agrupa a los procesos que están
en estado de ejecución (TASK_RUNNING)
1 Los procesos que estén en TASK_ZOMBIE, o
TASK_STOPPED no requieren ser agrupados ya que
su padre los recupera a partir de su PID.
1 Los procesos que estén en estado
TASK_INTERRUPTIBLE o TASK_UNINTERRUPTIBLE
pueden ser agrupados según varios criterios, de
modo que para ser recuperados se requiere mas
información que la de su Descriptor de proceso.
Autor: Alejandro Furfaro
109
Device Drivers: Hands On! (10)
Colas de espera - ¿qué esperan?
1 El
kernel utiliza a las colas de espera para:
2 Manejo
de interrupciones (espera un carácter o un bloque
de caracteres por un port)
2 Sincronización de procesos (espera a que se libere un
recurso)
2 Temporización (espera que transcurrar una demora
determinada)
1 Las
colas de espera agrupan a los procesos en
diferentes listas para esperar por eventos. Solo el
kernel espera el evento. De este modo con la
ayuda de las colas de espera el kernel “duerme” al
proceso, hasta que llegue el evento.
1 El kernel detecta los eventos y despierta al proceso
de la lista que lo esté esperando.
Autor: Alejandro Furfaro
110
Device Drivers: Hands On! (11)
Colas de espera: estructura
1
Para esperar un evento, un proceso crea una cola de espera.
1
El kernel 2.4, incorpora mejoras en el manejo de listas
doblemente enlazadas, cuyos elemento apuntan a
descriptores de procesos.
1 Cada lista comienza con un elemento de encabezado
struct __wait_queue_head {
spinlock_t lock;//previene locks en accesos concurrentes
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
1 Luego cada elemento es una estructura del tipo:
struct __wait_queue {
unsigned int flags;
//1 para procesos exclusivos. 0 de
otro modo
struct task_struct * task;
struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;
Autor: Alejandro Furfaro
111
Device Drivers: Hands On! (12)
Colas de espera: estructura (2)
1
Procesos exclusivos: El kernel los despierta
1
Cuando se quiere definir una cola de mensajes se
utiliza el siguiente código:
# include <linux/wait.h>
wait_queue_head_t my_queue;
init_waitqueue_head (&my_queue);
/*Otra forma de declarar una cola de espera es en forma
estática (no como una variable automática de un procedimiento
o como resultado de alocar dinámicamente una estructura ), se
hace del siguiente modo: DECLARE_WAIT_QUEUE_HEAD (my_queue);
*/
Autor: Alejandro Furfaro
112
Device Drivers: Hands On! (13)
Colas de espera: estructura (3)
wait_queue_head_t
Cola
Colade
deespera
esperavacía
vacía::
Ningún
Ningúnproceso
procesoduerme
duermeen
enella
ella
struct task_struct * task
spinlock_t lock
struct list_head task_list
struct list_head task_list
wait_queue_head_t
struct task_struct * task
spinlock_t lock
Proceso
Procesoactual
actual(current)
(current)
durmiendo
en
una
durmiendo en unacola
colade
de
espera
espera
struct list_head task_list
struct list_head task_list
Diversos
DiversosProcesos
Procesosdurmiendo
durmiendo
en
una
misma
cola
de
en una misma cola deespera
espera
wait_queue_head_t
spinlock_t lock
struct task_struct * task
struct task_struct * task
struct list_head task_list
struct list_head task_list
struct list_head task_list
Autor: Alejandro Furfaro
113
Device Drivers: Hands On! (14)
Colas de espera: funcionamiento (1)
1 El
kernel utiliza un set de funciones para
administrar las colas de mensajes:
2 init_waitqueue_head
(q):
(q) inicializa una cola de espera
vacía.
2 add_wait_queue (q, entry): inserta un proceso no
exclusivo con dirección entry a la cola q.
2 add_wait_queue_exclusive (q, entry): inserta un
proceso exclusivo en la última posición de una cola
2 remove_wait_queue (q, entry): remueve un elemento
con dirección entry a la cola q.
2 waitqueue_active( ): Chequea si una cola de espera
está vacía
Autor: Alejandro Furfaro
114
Device Drivers: Hands On! (15)
Colas de espera: funcionamiento (2)
1
Cuando un proceso necesita esperar un evento tiene varias
funciones a su disposición:
2
2
2
sleep_on():
() Pone al proceso en estado TASK_UNINTERRUPTIBLE, lo
inserta en la cola de espera, e invoca al scheduler para que pase al siguiente
proceso. Cuando el proceso insertado en la cola de espera se despierta,
llama al scheduler para retomar la ejecución de ese proceso
void sleep_on (wait_queue_head_t *q) {
unsigned long flags;
struct wait_queue_t wait;
wait.flags = 0;
wait.task = current;
add_wait_queue (q, &wait);
current->state = TASK_UNINTERRUPTIBLE; //Proceso sleeping.
add_wait_queue(q, &wait);
schedule( );
remove_wait_queue(q, &wait);
}
Interruptible_sleep_on(): Es idéntica a sleep_on () con la única diferencia
que el proceso se pone en estado TASK_INTERRUPTIBLE
sleep_on_timeout() e interruptible_sleep_on_timeout(): Iguales a las
anteriores, le permiten a la aplicación definir y enviar como parámetro un
tiempo máximo para la espera del evento.
115
Autor: Alejandro Furfaro
ANEXOS
Estructuras y piezas de código
Autor: Alejandro Furfaro
116
task_struct
(/usr/src/linux-[version]/includes/linux/sched.h)
-[version]
struct task_struct {
/*
* offsets of these are hardcoded elsewhere - touch with care
*/
volatile long state;
/* -1 unrunnable, 0 runnable, >0 stopped */
unsigned long flags;
/* per process flags, defined below */
int sigpending;
typedef struct {
mm_segment_t addr_limit; /* thread address space:
unsigned long seg;
0-0xBFFFFFFF for user-thead
} mm_segment_t;
0-0xFFFFFFFF for kernel-thread
*/
/*Process Excecution Domain */
struct exec_domain *exec_domain;
volatile long need_resched;
unsigned long ptrace;
int lock_depth;
/* Lock depth */
/*
* offset 32 begins here on 32-bit platforms. We keep
* all fields in a single cacheline that are needed for
* the goodness() loop in schedule().
*/
Autor: Alejandro Furfaro
117
task_struct
(/usr/src/linux-[version]/includes/linux/sched.h)
-[version]
long counter;
long nice;
unsigned long policy;
struct mm_struct *mm;
int processor;
/*
* cpus_runnable is ~0 if the process is not running on any
* CPU. It's (1 << cpu) if it's running on a CPU. This mask
* is updated under the runqueue lock.
*
* To determine whether a process might run on a CPU, this
* mask is AND-ed with cpus_allowed.
*/
unsigned long cpus_runnable, cpus_allowed;
/*
* (only the 'next' pointer fits into the cacheline, but
* that's just fine.)
*/
struct list_head run_list;
unsigned long sleep_time;
Autor: Alejandro Furfaro
118
task_struct
(/usr/src/linux-[version]/includes/linux/sched.h)
-[version]
struct task_struct *next_task, *prev_task;
struct mm_struct *active_mm;
struct list_head local_pages;
unsigned int allocation_order, nr_local_pages;
/* task state */
struct linux_binfmt *binfmt;
int exit_code, exit_signal;
int pdeath_signal; /* The signal sent when the parent dies */
/* ??? */
unsigned long personality;
int did_exec:1;
unsigned task_dumpable:1;
pid_t pid;
pid_t pgrp;
pid_t tty_old_pgrp;
pid_t session;
pid_t tgid;
/* boolean value for session group leader */
int leader;
Autor: Alejandro Furfaro
119
task_struct
(/usr/src/linux-[version]/includes/linux/sched.h)
-[version]
/*
* pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->p_pptr->pid)
*/
struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
struct list_head thread_group;
/* PID hash table linkage. */
struct task_struct *pidhash_next;
struct task_struct **pidhash_pprev;
wait_queue_head_t wait_chldexit;
/* for wait4() */
/* for vfork() */
struct completion *vfork_done;
unsigned long rt_priority;
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
struct timer_list real_timer;
struct tms times;
unsigned long start_time;
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
Autor: Alejandro Furfaro
120
task_struct
(/usr/src/linux-[version]/includes/linux/sched.h)
-[version]
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
int swappable:1;
/* process credentials */
uid_t uid,euid,suid,fsuid;
gid_t gid,egid,sgid,fsgid;
int ngroups;
gid_t groups[NGROUPS];
kernel_cap_t cap_effective, cap_inheritable, cap_permitted;
int keep_capabilities:1;
struct user_struct *user;
/* limits */
struct rlimit rlim[RLIM_NLIMITS];
unsigned short used_math;
char comm[16];
/* file system info */
int link_count, total_link_count;
/* NULL if no tty */
struct tty_struct *tty;
unsigned int locks;
/* How many file locks are being held */
/* ipc stuff */
struct sem_undo *semundo;
struct sem_queue *semsleeping;
Autor: Alejandro Furfaro
121
task_struct
(/usr/src/linux-[version]/includes/linux/sched.h)
-[version]
/* CPU-specific state of this task */
struct thread_struct thread;
/* filesystem information */
struct fs_struct *fs;
/* open file information */
struct files_struct *files;
/* namespace */
struct namespace *namespace;
/* signal handlers */
spinlock_t sigmask_lock;
/* Protects signal and blocked */
struct signal_struct *sig;
sigset_t blocked;
struct sigpending pending;
unsigned long sas_ss_sp;
size_t sas_ss_size;
int (*notifier)(void *priv);
void *notifier_data;
sigset_t *notifier_mask;
Autor: Alejandro Furfaro
122
task_struct
(/usr/src/linux-[version]/includes/linux/sched.h)
-[version]
/* Thread group tracking */
u32 parent_exec_id;
u32 self_exec_id;
/* Protection of (de-)allocation: mm, files, fs, tty */
spinlock_t alloc_lock;
/* journalling filesystem info */
void *journal_info;
};
Autor: Alejandro Furfaro
123
mm_segment_t
(/usr/src/linux-[version]/includes/asm-i386/processor.h)
-[version]
typedef struct {
unsigned long seg;
} mm_segment_t;
Autor: Alejandro Furfaro
124
exec_domain
(/usr/src/linux-[version]/includes/linux/personality.h)
-[version]
struct exec_domain {
const char
handler_t
unsigned char
unsigned char
unsigned long
unsigned long
struct map_segment
struct map_segment
struct map_segment
struct map_segment
struct module *module;
struct exec_domain
};
Autor: Alejandro Furfaro
*name;
handler;
pers_low;
pers_high;
*signal_map;
*signal_invmap;
*err_map;
*socktype_map;
*sockopt_map;
*af_map;
*next;
/* name of the execdomain */
/* handler for syscalls */
/* lowest personality */
/* highest personality */
/* signal mapping */
/* reverse signal mapping */
/* error mapping */
/* socket type mapping */
/* socket option mapping */
/* address family mapping */
/* module context of the ed. */
/* linked list (internal) */
125
mm_struct
(/usr/src/linux-[version]/includes/linux/sched.h)
-[version]
struct mm_struct {
struct vm_area_struct * mmap;
/* list of VMAs */
rb_root_t mm_rb;
struct vm_area_struct * mmap_cache; /* last find_vma result */
pgd_t * pgd;
atomic_t mm_users;
/* How many users with user space? */
atomic_t mm_count;
/* How many references to "struct mm_struct" (users count as 1) */
int map_count;
/* number of VMAs */
struct rw_semaphore mmap_sem;
spinlock_t page_table_lock;
/* Protects task page tables and mm->rss */
struct list_head mmlist;
/* List of all active mm's. These are globally strung together off
*init_mm.mmlist, and are protected by mmlist_lock */
unsigned long start_code, end_code, start_data, end_data;
unsigned long start_brk, brk, start_stack;
unsigned long arg_start, arg_end, env_start, env_end;
unsigned long rss, total_vm, locked_vm;
unsigned long def_flags;
unsigned long cpu_vm_mask;
unsigned long swap_address;
unsigned dumpable:1;
mm_context_t context;
/* Architecture-specific MM context */
};Autor: Alejandro Furfaro
126
list_head
(/usr/src/linux-[version]/includes/linux/list.h)
-[version]
struct list_head {
struct list_head *next, *prev;
};
Autor: Alejandro Furfaro
127
linux_binfmt
(/usr/src/linux-[version]/includes/linux/binfmts.h)
-[version]
/*
* This structure defines the functions that are used to load the binary formats that
* linux accepts.
*/
struct linux_binfmt {
struct linux_binfmt * next;
struct module *module;
int (*load_binary)(struct linux_binprm *, struct pt_regs * regs);
int (*load_shlib)(struct file *);
int (*core_dump)(long signr, struct pt_regs * regs, struct file * file);
unsigned long min_coredump;
/* minimal dump size */
};
Autor: Alejandro Furfaro
128
completion
(/usr/src/linux-[version]/includes/linux/completion.h)
-[version]
struct completion {
unsigned int done;
wait_queue_head_t wait;
};
Autor: Alejandro Furfaro
129
timer_list
(/usr/src/linux-[version]/includes/linux/timer.h)
-[version]
/*
* In Linux 2.4, static timers have been removed from the kernel.
* Timers may be dynamically created and destroyed, and should be initialized
* by a call to init_timer() upon creation.
*
* The "data" field enables use of a common timeout function for several
* timeouts. You can use this field to distinguish between the different
* invocations.
*/
struct timer_list {
struct list_head list;
unsigned long expires;
unsigned long data;
void (*function)(unsigned long);
};
Autor: Alejandro Furfaro
130
tms
(/usr/src/linux-[version]/includes/linux/times.h)
-[version]
struct tms {
clock_t tms_utime;
clock_t tms_stime;
clock_t tms_cutime;
clock_t tms_cstime;
};
Autor: Alejandro Furfaro
131
user_struct
(/usr/src/linux-[version]/includes/linux/sched.h)
-[version]
/*
* Some day this will be a full-fledged user tracking system..
*/
struct user_struct {
atomic_t __count;
/* reference count */
atomic_t processes;
/* How many processes does this user have? */
atomic_t files;
/* How many open files does this user have? */
/* Hash table maintenance information */
struct user_struct *next, **pprev;
uid_t uid;
};
Autor: Alejandro Furfaro
132
rlimit
(/usr/src/linux-[version]/includes/linux/resources.h)
-[version]
struct rlimit {
unsigned long rlim_cur;
unsigned long rlim_max;
};
Autor: Alejandro Furfaro
133
tty_struct
(/usr/src/linux-[version]/includes/linux/tty.h)
-[version]
struct tty_struct {
int
magic;
struct tty_driver driver;
struct tty_ldisc ldisc;
struct termios *termios, *termios_locked;
int pgrp, session;
kdev_t device;
unsigned long flags;
int count;
struct winsize winsize;
unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
unsigned char low_latency:1, warned:1;
unsigned char ctrl_status;
struct tty_struct *link;
struct fasync_struct *fasync;
struct tty_flip_buffer flip;
int max_flip_cnt;
int alt_speed;
/* For magic substitution of 38400 bps */
wait_queue_head_t write_wait;
wait_queue_head_t read_wait;
struct tq_struct tq_hangup;
void *disc_data;
Autor: Alejandro Furfaro
134
tty_struct
(/usr/src/linux-[version]/includes/linux/tty.h)
-[version]
void *driver_data;
struct list_head tty_files;
#define N_TTY_BUF_SIZE 4096
/* The following is data for the N_TTY line discipline. For historical reasons, this is included in the
tty structure./
unsigned int column;
unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
unsigned char closing:1;
unsigned short minimum_to_wake;
unsigned long overrun_time;
int num_overrun;
unsigned long process_char_map[256/(8*sizeof(unsigned long))];
char *read_buf;
int read_head, read_tail, read_cnt;
unsigned long read_flags[N_TTY_BUF_SIZE/(8*sizeof(unsigned long))];
int canon_data;
unsigned long canon_head;
unsigned int canon_column;
struct semaphore atomic_read
struct semaphore atomic_write;
spinlock_t read_lock;
struct tq_struct SAK_tq; /* If the tty has a pending do_SAK, queue it here - akpm */
}; Autor: Alejandro Furfaro
135
thread_struct
(/usr/src/linux-[version]/includes/asm-i386/processor.h)
-[version]
struct thread_struct {
unsigned long
esp0;
unsigned long
eip;
unsigned long
esp;
unsigned long
fs;
unsigned long
gs;
/* Hardware debugging registers */
unsigned long
debugreg[8]; /* %%db0-7 debug registers */
/* fault info */
unsigned long
cr2, trap_no, error_code;
/* floating point info */
union i387_union i387;
/* virtual 86 mode info */
struct vm86_struct
* vm86_info;
unsigned long
screen_bitmap;
unsigned long
v86flags, v86mask, saved_esp0;
/* IO permissions */
int
ioperm;
unsigned long
io_bitmap[IO_BITMAP_SIZE+1];
};
Autor: Alejandro Furfaro
136
fs_struct
(/usr/src/linux-[version]/includes/linux/processor.h)
-[version]
struct fs_struct {
atomic_t count;
rwlock_t lock;
int umask;
struct dentry * root, * pwd, * altroot;
struct vfsmount * rootmnt, * pwdmnt, * altrootmnt;
};
Autor: Alejandro Furfaro
137
files_struct
(/usr/src/linux-[version]/includes/linux/sched.h)
-[version]
/*
* Open file table structure
*/
struct files_struct {
atomic_t count;
rwlock_t file_lock;
/* Protects all the below members. Nests inside tsk->alloc_lock */
int max_fds;
int max_fdset;
int next_fd;
struct file ** fd;
/* current fd array */
fd_set *close_on_exec;
fd_set *open_fds;
fd_set close_on_exec_init;
fd_set open_fds_init;
struct file * fd_array[NR_OPEN_DEFAULT];
};
Autor: Alejandro Furfaro
138
namespace
(/usr/src/linux-[version]/includes/linux/namespace.h)
-[version]
struct namespace {
atomic_t
struct vfsmount *
struct list_head
struct rw_semaphore
};
Autor: Alejandro Furfaro
count;
root;
list;
sem;
139
signal_struct
(/usr/src/linux-[version]/includes/linux/sched.h)
-[version]
struct signal_struct {
atomic_t
struct k_sigaction
spinlock_t
};
Autor: Alejandro Furfaro
count;
action[_NSIG];
siglock;
140
sigpending
(/usr/src/linux-[version]/includes/linux/signal.h)
-[version]
struct sigpending {
struct sigqueue *head, **tail;
sigset_t signal;
};
Autor: Alejandro Furfaro
141
Descargar