La shell puede arrancar un comando mediante un fork() y luego un exec() y
esperar a que este muera. Recuerde que la función exec() no tiene retorno
posible ya que finaliza con la muerte del proceso. En ese momento
la shell detecta la muerte de su hijo y continua su ejecución solicitando
la entrada de un nuevo comando. Cuando introducimos el comando 'exit' estamos
indicando a la shell que finalice y su padre 'init' se encargará de lanzar
nuevo proceso 'getty'. Lógicamente 'exit' es un comando interno de la shell.
Quizas le llame la atención que la muerte de 'bash'
termine provocando un nuevo 'getty' cuando 'getty' pasó a 'login' y este a
'bash' pero en esta secuencia getty-login-bash no hay ningún fork() por eso
getty, login, y bash son en realidad el mismo proceso en distintos momentos
con el mismo PID obtenido en el fork() realizado por 'init' solo que ha ido
cambiando su personalidad manteniendo la misma identidad (mismo PID).
Para 'init' siempre se trató del mismo hijo y la muerte de cualquiera
de ellos (getty, login o bash) provoca que se arranque
un nuevo 'getty' sobre ese mismo terminal con el fin de que ese terminal
no quede sin servicio.
La presentación del mensaje de Login es mostrada por 'getty'.
Una vez introducido el identificador de usuario será 'login' quien
muestre la solicitud de introducción de la password, y una vez
introducido el password será la shell quien muestre el introductor
de comandos pero estamos hablando siempre del mismo proceso.
A modo de ejercicio compruebe estas cosas por usted mismo
usando algunos de los comandos que ya conoce. Para hacer
esta práctica no basta con usar un terminal remoto sino
que necesitará un PC completo para ir haciendo cosas desde
distintas sesiones.
Le proponemos hacerlo más o menos de la siguiente manera:
- Entre en cada uno de los terminales disponibles de forma que todos
los terminales esten ocupados por un interprete de comandos. Bastará
con hacer login en todos ellos.
- Luego compruebe que no hay ningún proceso 'getty'.
- Haga un exit desde uno de estos terminales.
- Compruebe desde otro termina que ahora si existe un proceso
'getty' y anote su pid.
- Introduzca el nombre de usuario en ese terminal que quedó libre.
- Compruebe ahora desde otra sesion que existe un proceso login con
el PID que usted anotó.
- Termine de indentificarse tecleando la password
- Compruebe desde otra sesión que ahora existe una shell con el PID
que anotamos.
Si no tiene el comando 'pstree' tendrá que usar 'ps' pero con pstree
puede ver más facilmente lo que ocurrirá ahora.
- Ahora teclee el comando 'sleep 222' desde la sesión que tiene el
PID anotado por usted.
- Compruebe desde otra sesión que el interprete de comandos ha
realizado un fork() generando un comando que está ejecutando el
comando indicado.
Si no ha podido realizar el ejercicio anterior tendrá que confiar en que
las cosas son como decimos y ya está.
La mayoría de los comandos están gran parte del tiempo sin consumir CPU
porque necesitan esperar para hacer entrada salida sobre dispositivos
lentos que además pueden estar en uso compartidos por otros procesos.
Existe un comando capaz de esperar tiempo sin gastar tiempo de CPU.
Se trata del comando 'sleep'. Para usarlo le pasaremos un argumento que
indique el número de segundos de dicha espera.
Por ejemplo vamos a comprobar cuanta CPU consume una espera
de 6 segundos usando sleep
$ time sleep 6
real 0m6.021s
user 0m0.020s
sys 0m0.000s
|
El resultado obtenido puede variar ligeramente en cada sistema pero
básicamente obtendrá un tiempo 'real' de unos 6 segundos y un tiempo de
CPU ( 'user' + 'sys' ) muy pequeño.
Vamos a medir tiempos en un comando que realice operaciones de entrada
salida así como proceso de datos.
$ time ls /* > /dev/null
real 0m0.099s
user 0m0.080s
sys 0m0.010s
|
En este comando verá que el consumo total de CPU es superior al del
comando sleep. En cualquier caso el tiempo real tardado en la ejecución
del comando es siempre muy superior al consumo de CPU.
Vamos a probar un comando que apenas realice otra cosa que
entrada salida. Vamos a enviar 10Mbytes al dispositivo /dev/null.
Existe un comando 'yes' que provoca la salida continua de un caracter
'y' seguido de un caracter retorno de carro. Esta pensado para sustituir
la entrada de un comando interactivo en el cual queremos contestar
afirmativamente a todo lo que pregunte. Nosotros fitraremos la salida
de 'yes' con el comando 'head' para obtener solo los 10Mbytes primeros
producidos por 'yes' y los enviaremos al dispositivo nulo '/dev/null'
que viene a ser un pozo sin fondo en el cual podemos introducir cualquier
cosa sin que se llene, pero no podremos sacar absolutamente nada. En una
palabra vamos a provocar proceso de entrada salida perfectamente inutil.
time yes | head --bytes=10000000 > /dev/null
Tubería rota
real 0m6.478s
user 0m5.440s
sys 0m0.900s
|
Podemos hacer un consumo fuerte de CPU si forzamos a cálculos masivos
que no tengan apenas entrada salida. Por ejemplo podemos poner a
calcular el número PI con 300 cifras decimales. 'bc' es un comando
que consiste en una calculadora. Admite uso interactivo pero tambien
acepta que le pasemos las operaciones desde otro proceso combinando
entrada salida.
time ( echo "scale=300; 4*a(1)" | bc -l )
3.141592653589793238462643383279502884197169399375105820974944592307\
81640628620899862803482534211706798214808651328230664709384460955058\
22317253594081284811174502841027019385211055596446229489549303819644\
28810975665933446128475648233786783165271201909145648566923460348610\
454326648213393607260249141272
real 0m2.528s
user 0m2.520s
sys 0m0.010s
|
En un Pentium 200Mhz este comando tardó 3 segundos para 300 cifras y 20
segundos usando 600 cifras. Decimos esto para que vea que el tiempo
que se tarda aumenta exponencialmente y que dependiendo de la potencia
de su ordenador puede suponer bastante tiempo de proceso. Quizas tenga
que variar el número de cifras significativas para poder medir tiempos
con comodidad.
Este comando 'time' es un comando interno pero en Linux también hay
un comando externo llamado de la misma forma. Para poder ejecutarlo
con esta shell debería incluir el camino completo. No deseamos abusar
de su escaso 'time' así que no lo comentaremos. Para buscar en el
man el comando 'time' que hemos explicado o de cualquier otro comando
interno tendría que mirar en la página del manual de bash.