Llamadas al Sistema
EXIT y WAIT
Alumnos :
Cristo Manuel Alonso Santana
Inti Sologuren Marrero
Llamada al sistema exit
 La finalidad de exit() es poner fin a la
existencia de un proceso.
 Está contenida en el fichero fuente:
kernel/exit.c
 Implementada por la función sys_exit(), la
llamada exit pasa por ser la llamada al
sistema número 1.
 Sys_exit() a su vez invoca a do_exit
pasándole el código de retorno
Perspectiva del Sistema Operativo
 Cuando se invoca a la
llamada exit(), el
sistema operativo
reacciona reclamando
todos los recursos que
tiene asociado el
proceso que ha de
finalizar.




Ficheros asociados
Sistema de Ficheros
Memoria utilizada
Señales pendientes
Sintaxis
void exit ()
 El valor devuelto al proceso padre será
cero en caso de finalización normal y
distinto a cero si finaliza debido a un error.
 Cuando el proceso hijo termina le envía al
padre una señal SIGCHLD y espera hasta
que el valor estado sea aceptado por el
padre, permaneciendo en estado zombie.
Implementación sys_exit()
int sys_exit (int error_code)
{
do_exit((error_code&0xff)<<8);
}
La función sólo convierte el código de retorno
al formato esperado por do_exit, que es quien
realmente lleva a cabo la implementación.
Descriptores de Proceso

Task struct


Estructura principal del proceso.
Files_struct


Referencia a los archivos asociados del proceso.
Fs_struct


Asocia el sistema de ficheros con el proceso
Signal_struct


Acciones asociadas a las señales del proceso.
Mm_struct


Memoria asociada
Namespace

Información acerca del sistema de ficheros
Task_struct
Struct task_struct
{
volatile long
state;
/*Estado del proceso (TASK ZOMBIE)*/
unsigned long flags;
/*Información adicional(PF_EXITING)*/
int
exit_code; /*Exit code para el padre*/
int
pid;
/*Sistema de ficheros*/
struct fs_struct* fs;
/*Sistema de ficheros*/
struct mm_struct* mm
/*Memoria asociada*/
struct files_struct* files; /*Ficheros asociados*/
struct signal_struct* sig; /*Acciones asociadas*/
struct namespace* namespace; /*Información del Sist. Ficheros.*/
}
Struct fs_struct
Struct fs_struct
{
int
count; /* Nº de procesos que referencian este handle*/
struct inode* root; /*Directorio raíz*/
struct inode* pwd; /* Directorio actual*/
}
Struct signal_struct
Struct signal_struct
{
int
count
; /*Nº de descriptores de archivos asociados*/
struct k_sigaction[32] action; */ Tabla de funciones de desvío*/
}
Struct files_struct
Struct files_struct
{
int
struct file*
}
count;
fd;
/*Nº de descriptores de archivos asociados*/
/*Lista de descriptores de archivos abiertos*/
Struct file
Struct file
{
loff_t
struct file*
struct file*
}
f_pos; /*Posición actual desde el inicio del fichero*/
f_next; /*Siguiente descriptor*/
f_prev; /*Anterior descriptor*/
Struct mm_struct
Struct mm_struct
{
int
pgd_t
/*Número de referencias (procesos)*/
/*Dirección de la tabla global de páginas
utilizada por el proceso*/
unsigned long start_code;
*/Inicio del código del proceso en
memoria*/
unsigned long end_code;
/*Fin del código del proceso en
memoria*/
unsigned long start_data;
/*Inicio del segmento de datos*/
unsigned long end_data;
/*Fin del segmento de datos*/
}
count;
pgd;
Struct namespace
Struct namespace
{
int
count;
struct vfsmount* root; /*Sistema de ficheros sobre el
que está el proceso*/
}
Funcionamiento
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
Obtención del proceso a terminar
Comprobaciones previas
Informar de que el proceso está terminado
Eliminar su temporizador
Libera la memoria asociada al proceso
Elimina cualquier semáforo pendiente
Libera los ficheros asociados al proceso
Libera los directorios raíz y actual del proceso
Libera la información del sistema de ficheros
Libera las acciones asociadas a las señales pendientes
Elimina el hilo actual vinculado al proceso
Desvincula la terminal asociada al proceso
Acciones sobre el ámbito de ejecución
Almacenamiento del código de retorno
Advertencia al padre de la finalización de uno de sus hijos
Cambio de contexto
do_exit
void do_exit(long code)
{
struct task_struct *tsk = current; //Obtenemos el proceso
//Hacemos algunas comprobaciones antes de proceder
if (in_interrupt()) /*Si el sistema está en una interrupción*/
panic(“aiee, kiling interrupt handler!”);
if (!tsk->pid) /*¿Matar un proceso con pid 0?
tarea inactiva*/
panic(“Attempted to kill the idle task!”);
if (tsk->pid==1) /*¿Matar el proceso init?*/
panic(“Attempted to kill init!”);
….
do_exit
void do_exit()
{
….
tsk->flags |= PF_EXITING;
/*Informa de que el proceso está
terminado*/
del_timer_sync(&tsk->real_timer);
/ *Elimina su temporizador de
la lista*/
__exit_mm(tsk);
/*Libera el espacio de direccionamiento del
proceso*/
lock_kernel(); /*Hecha cerrojo al kernel*/
sem_exit(); /*Si el proceso estaba esperando por un semáforo, lo
elimina de la cola asociada a dicho semáforo*/
__exit_files(tsk); /*Libera los ficheros asociados al proceso*/
….
do_exit
void do_exit()
{
….
__exit_fs(tsk);
exit_namespace();
/*Elimina toda información que relaciona el
sistema de ficheros de un proceso*/
/*Borra las entradas y dependencias de los
sistemas de ficheros, directorio raiz, etc*/
/*Libera las acciones asociadas a las señales*/
/*Elimina el hilo actual vinculado al proceso*/
exit_sighand(tsk);
exit_thread();
if (current->leader)
disassociate_ctty(1); /*Elimina el vínculo entre el proceso y
la terminal correspondiente*/
….
do_exit
void do_exit()
{
….
put_exec_domain(tsk->exec_domain);/*Acciones sobre el ámbito de
ejecución*/
/*Acciones sobre el formato del archivo ejecutable*/
if (tsk->binfmt && tsk->binfmt->module)
__MOD_DEC_USE_COUNT(tsk->binfmt->module);
tsk->exit_code = code; /*Almacena el código de retorno*/
exit_notify(); /*Establece el estado del proceso como
TASK_ZOMBIE y Advierte al proceso padre de la
finalización de uno de sus hijos*/
shedule(); /*Realiza un cambio de contexto*/
BUG();
}
Funciones complementarias
void __exit_mm(struct task_struct * tsk)
{
struct mm_struct * mm = tsk->mm;
mm_release(); /*Libera la memoria*/
if (mm) {
atomic_inc(&mm->mm_count);
BUG_ON(mm != tsk->active_mm);
task_lock(tsk);
tsk->mm = NULL;/*Elimina toda la referencia a memoria*/
task_unlock(tsk);
enter_lazy_tlb(mm, current, smp_processor_id());
mmput(mm);/*Devuelve al sistema los recursos asociados al
proceso*/
}
Funciones complementarias
void __exit_files(struct task_struct *tsk)
{
/*Obtenemos los ficheros asociados al proceso*/
struct files_struct * files = tsk->files;
if (files) /*Si tiene ficheros abiertos…*/
{
task_lock(tsk);
tsk->files = NULL;/*…eliminamos los vínculos a los mismos*/
task_unlock(tsk);
put_files_struct(files);
}
}
Funciones complementarias
void __exit_fs(struct task_struct *tsk)
{
struct fs_struct * fs = tsk->fs;
if (fs) /*…Si existe información de control de acceso*/
{
task_lock(tsk);
tsk->fs = NULL;/*…la eliminamos*/
task_unlock(tsk);
__put_fs_struct(fs);
}
}
Funciones complementarias
void exit_namespace(struct task_struct *p)
{
/*Obtenemos la información del espacio de nombres asociado al
descriptor del proceso*/
struct namespace *namespace = p->namespace;
if (namespace) {
task_lock(p); /*Se bloquea la tarea…*/
p->namespace = NULL; /*…Elimina la
información*/
task_unlock(p);
put_namespace(namespace);
}
}
Funciones complementarias
void exit_sighand(struct task_struct *tsk)
{
/*Obtenemos los descriptores de acciones asociadas al proceso*/
struct signal_struct * sig = tsk->sig;
spin_lock_irq(&tsk->sigmask_lock);/*Hecha cerrojo*/
if (sig) /*Si hay acciones pendientes…*/
{
tsk->sig = NULL;/*…las eliminamos*/
/*Decrementa el nº de procesos que apuntan a la tabla de funciones de desvío
y se libera el espacio de memoria que ocupan*/
if (atomic_dec_and_test(&sig->count))
kmem_cache_free(sigact_cachep, sig);
}
tsk->sigpending = 0; /*Reiniciamos el número de acciones pendientes*/
flush_sigqueue(&tsk->pending);
spin_unlock_irq(&tsk->sigmask_lock); /*Desbloquea el cerrojo*/
}
Llamada al sistema Wait
 Es la llamada al sistema num. 114
 Su función es la de hacer esperar a un
proceso, por la finalización de uno de sus
hijos.
 Implementada por la función sys_wait4
 Contenida en el fichero fuente:
 kernel/exit.c
Interfaz sys_waitpid
 Función que se mantiene por
compatibilidad, lo único que hace es
llamar a sys_wait4 con los mismo
parámetros.
Ejemplo de uso








/*Programa de usuario*/
void main ()
{
fork ();
...
wait(pid);
...
}
 Cuando el proceso padre
invoca al wait,…
 …detiene su ejecución
hasta que el proceso hijo
con el pid especificado,…
 ...finaliza, haciendo una
llamada al sistema por
medio del exit...
 ... o bien termina la
ejecución de su código
Interfaz sys_wait4
 Parámetros
pid_t pid /* identificador del proceso por el que se va a esperar*/
unsigned int* stat_addr /* Dirección donde se copiará el estado
de finalización del hijo*/
int options /* Define el comportamiento de sys_wait4*/
struct rusage* ru /* Dirección donde se indica la información de
recursos usados por el proceso a esperar*/
 Valor de retorno
Devuelve el código de retorno del proceso hijo por el
cual se espera, en forma de entero
Interfaz sys_wait4
 El valor que tenga el parámetro PID tiene los
siguientes significados:
- < -1 : Esperar por cualquier hijo cuyo ID de grupo sea
igual al valor del pid (con el signo cambiado).
- -1 : Esperar por el primer hijo que termine.
- 0 : Esperar por cualquier hijo cuyo identificador de
grupo sea igual al pid del proceso llamador (padre).
- > 0 : Esperar por los hijos cuyo pid es el indicado.
Descriptores de ficheros
 Struct task_struct {
 pid_t pid; /*identificador de proceso*/
 pid_t pgrp; /*identificador de grupo*/
 wait_queue_head_t wait_chldexit; /*referencia a la cola de
espera*/
 volatile long state; /*estado actual del proceso*/
 int exit_code; /*codigo de salida*/
 int exit_signal; /*señal de salida*/
 struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_osptr; /*puntero
al padre original, al padre actual, al hijo y al hermano mas viejo*/
}
Descriptores de ficheros
 State puede tener 5 valores:
 TASK_RUNNING: El proceso está en ejecución o
esperando para ser ejecutado.
 TASK_INTERRUPTIBLE: El proceso se encuentra
suspendido a la espera de que ocurra algún evento.
 TASK_UNINTERRUPTIBLE: Igual que el estado
anterior pero una señal no despertará al proceso.
 TASK_STOPPED: La ejecución del proceso ha sido
interrumpida al recibir una señal SIGSTOP, SIGTSTP,
SIGTTIN o SIGTTOU.
 TASK_ZOMBIE: El proceso ha terminado de
ejecutarse pero está esperando a que el padre haga
un wait() (o muera).
Funcionamiento
 Verifica que las opciones son válidas.
 Añade el proceso actual a la cola de procesos
en espera.
 Para cada uno de los hijos del proceso:
 Busca un proceso hijo con el pid correspondiente
 Comprueba si es clónico o no
 Pregunta por el estado del proceso
 Pone el valor de retorno correspondiente.
 Saca el proceso actual de la cola de espera.
 Devuelve el valor de retorno.
sys_wait4
/*Verifica que las opciones son válidas.*/
….
if(options & ~(WNOHANG|WUNTRACED|__WCLONE))
return -EINVAL;
….
/*Si las opciones no son las esperadas, devuelve el valor “Argumento
no válido” (EINVAL)
WNOHANG : salir inmediatamente si no termina ningún hijo.
WUNTRACED : si el hijo está detenido y su estado es desconocido se
pasa al próximo hijo.
_WCLONE : si se indica sólo se espera por los hijos clónicos, si no es
así, por los que no lo son (un hijo clónico es aquel que no envía
ninguna señal al padre salvo SIGCHLD hasta que finaliza)*/
sys_wait4
/*Añade el proceso actual a la cola de procesos en espera, identificado
por el campo wait_chldexit.*/
….
add_wait_queue(&current->wait_chldexit,&wait);
repeat:
….
/*Para cada uno de los hijos del proceso*/
….
for (p = current->p_cptr ; p ; p = p->p_osptr)
….
sys_wait4
/*Busca un proceso hijo con el pid correspondiente*/
…
if (pid>0) {
if (p->pid != pid) //¿Distinto pid?
continue;
} else if (!pid) { //Si es cero
if (p->pgrp != current->pgrp)
continue;
} else if (pid != -1) { //Si es distinto a -1
if (p->pgrp != -pid) //si pid de grupo es distinto a -pid
continue;
}
...
sys_wait4
/*Comprueba si es clónico o no*/
…
if (((p->exit_signal != SIGCHLD) ^((options & __WCLONE) != 0)) &&
!(options & __WALL))
continue;
…
/*Pregunta por el estado del proceso*/
…
switch (p->state) {
…
sys_wait4
….
case TASK_STOPPED:
if (!p->exit_code) //Si código de salida es cero
continue; // pasa a otro hijo
/* Se comprueba la bandera WUNTRACED*/
if (!(options & WUNTRACED) && !(p->ptrace & PF_PTRACED))
continue;
/*si ru no es nulo, calcula la cantidad de recursos consumidos por el
proceso actual y sus hijos, si no pone retval a cero*/
retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
….
sys_wait4
/*Copia el estado de finalización del hijo*/
….
if (!retval && stat_addr)
retval = put_user((p->exit_code << 8) | 0x7f,
stat_addr);
/*Antes de salir resetea el código de salida*/
if (!retval) {
p->exit_code = 0;
retval = p->pid;
}
/*saca el proceso actual de la cola de espera*/
goto end_wait4;
….
sys_wait4
….
case TASK_ZOMBIE:
/*Actualización de la información que tiene el padre sobre el tiempo de
usuario y del sistema usados por sus hijos*/
current->times.tm_cutime += p->times.tms_utime +
p->times.tms_cutime;
current->times.tm_cstime += p->times.tms_stime +
p->times.tms_cstime;
….
/*si ru no es nulo, calcula la cantidad de recursos consumidos por el
proceso actual y sus hijos, si no pone retval a cero*/
retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
sys_wait4
/*Copia el estado de finalización*/
if (!retval && stat_addr)
retval = put_user(p->exit_code, stat_addr);
/*Si el valor de retorno es > 0 vamos a end_wait4*/
if (retval)
goto end_wait4;
retval = p->pid; //asignamos al valor de retorno el pid del hijo
/*Se comprueba que el padre sea el padre original del proceso*/
if (p->p_opptr != p->p_pptr) { //si no es asi…
REMOVE_LINKS(p); //eliminamos los enlaces del hijo
p->p_pptr = p->p_opptr; //restauramos el padre original
SET_LINKS(p); //restauramos los enlaces
do_notify_parent(p, SIGCHLD); //notificación al padre del
cambio
sys_wait4
….
}else
release_task(p); //libera la tabla de tareas del hijo
goto end_wait4;
default:
//En cualquier otro caso busca el siguiente hijo
continue;
} //end switch
} //end for
} while (tsk != current); //end repeat
sys_wait4
/*Si existe algún proceso hijo con el pid indicado*/
….
if (flag) {
retval = 0
;
if (options & WNOHANG) /*Si WNOHANG activo sale
directamente*/
goto end_wait4;
/*Pone el valor de retorno a -ERESTARTSYS (La llamada al sistema
ha sido interrumpida por una señal; no se ha leído nada)*/
retval = -ERESTARTSYS;
/*Si el proceso actual tiene señales pendientes por tratar lo saca de la
cola de espera*/
if (signal_pending(current))
goto end_wait4;
sys_wait4
/*En caso contrario hace un cambio de contexto*/
schedule();
/*Se repite el proceso desde el principio*/
goto repeat;
}
/*Si no existe ningún proceso hijo, se devuelve -ECHILD (El proceso o
grupo de procesos indicado no existe o no es hijo del proceso que
llamó a la función) */
retval = -ECHILD;
/*Se suprime el proceso actual de la cola de espera.*/
end_wait4:
current->state = TASK_RUNNING; //pasa a estado de ejecución
remove_wait_queue(&current->wait_chldexit,&wait);
return retval;
}
Descargar

Llamadas al Sistema EXIT y WAIT - Servidor de Información de