Publicado el 22 de Abril del 2019
815 visualizaciones desde el 22 de Abril del 2019
154,2 KB
7 paginas
Creado hace 6a (22/03/2018)
Actividad 7 (v. 160322)
Depto. de Lenguajes y Sistemas Informáticos lsi.vc.ehu.es/pablogn
Pablo González Nalda
Llamadas al sistema básicas de control de procesos
fork, wait
1 #include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
4 #include <sys/types.h>
#include <sys/wait.h>
void main () {
int a, x, idh, ret;
a = 1;
printf("\nAntes del fork\n");
x=fork();
printf("\nDespuà cs del fork!!!!!!!!\n");
if (x==0) { // hijo
a = 2;
printf("\nSoy hijo %d \t a %d\n",getpid(), a);
exit(a);
}
else { // padre
printf("\nYo soy tu padre, a %d\n",a);
idh=wait(&ret);
printf("\nHijo terminado, a %d\n",a);
printf("\nidh %d \t ret %d\n",idh,ret/256);
7
10
13
16
19
22
7
10
13
16
}
}
}
}
Listing 1: Fichero a.c
Observa, analiza y prueba este programa y los siguientes.
Usa la llamada sleep(50) junto con exit(3) (código de salida 3) para que hijo o padre tarde más y
comprobar cómo queda el hijo zombi o huérfano. Usa ps aux o htop y pstree para observar los procesos.
fork+execlp+perror
Sustituir execlp por execl y comprobar la diferencia.
1 #include <stdio.h>
#include <string.h>
#include <unistd.h>
4 #include <sys/types.h>
#include <sys/wait.h>
void main (int argc, char * argv[]) {
int x, idh, ret;
x=fork();
if (x==0) { // hijo
execlp("ls","ls","-l", argv[1], NULL);
printf("AGGGGHH");
perror("no encuentro");
}
else { // padre
idh=wait(&ret);
printf("\nidh %d \t ret %d",idh,ret);
Listing 2: Fichero f.c
2
fork, wait y códigos de salida
Éste es un código más ordenado, que hace lo mismo pero procesa los valores con macros. Más adelante
veremos el caso de un proceso que termine por recibir una señal.
/* wait: parent waits for a child prcess to exit. */
/* The child runs "ls -aF /". The parent sleeps until the child is done
3 /* Paul Krzyzanowski */
*/
#include <stdlib.h> /* needed to define exit() */
6 #include <unistd.h> /* needed for fork() and getpid() */
#include <errno.h>
#include <stdio.h>
/* needed for errno */
/* needed for printf() */
int main(int argc, char **argv) {
void child(void); /* the child calls this */
void parent(int pid); /* the parent calls this */
int pid;
/* process ID */
switch (pid = fork()) {
case 0:
/* a fork returns 0 to the child */
child();
break;
default:
/* a fork returns a pid to the parent */
parent(pid);
break;
case -1:
/* something went wrong */
perror("fork");
exit(1);
}
exit(0);
}
void child(void) {
printf("About to run ls\n");
execlp("ls", "ls", "-aF", "/", (char*)0);
perror("execlp"); /* if we get here, execlp failed */
exit(1);
36 }
void parent(int pid) {
int got_pid, status;
/* wait woke up */
if (got_pid == pid)
9
12
15
18
21
24
27
30
33
39
42
45
48
51
54
57 }
while (got_pid = wait(&status)) {
/* go to sleep until something happens */
break;
/* this is what we were looking for */
if ((got_pid == -1) && (errno != EINTR)) {
/* an error other than an interrupted system call */
perror("waitpid");
return;
}
}
if (WIFEXITED(status)) /* process exited normally */
printf("child process exited with value %d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status)) /* child exited on a signal */
printf("child process exited due to signal %d\n", WTERMSIG(status));
else if (WIFSTOPPED(status))
/* child was stopped */
printf("child process was stopped by signal %d\n", WIFSTOPPED(status));
Listing 3: Fichero wait.c
3
argv,v
#include <stdio.h>
#include <string.h>
3 #include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
9
12
15
18
}
else {
}
21 }
6 main (int argc, char * argv[]) {
int x,p,r;
char ** v;
v = argv;
v++;
printf("\nv %s, %s\n", v[0],v[1]);
printf("\nargv %s, %s\n", argv[0],argv[1]);
x=fork();
if (x==0) {
execvp(argv[1], v);
p=wait(&r);
printf("\nRes=%d\n",r/256);
Listing 4: Fichero ejecuta.c
argv es un array de cadenas. El nombre de un vector o array es un puntero al primer elemento del vector,
y dado que cada elemento (cada cadena) es en realidad un puntero a carácter, el nombre del vector es un
puntero a punteros a carácter (**char).
4
Ejecuta diferentes comandos internos y externos
Como busybox, este programa muestra argv y es ejemplo de diferentes formas de ejecutar.
./box
./box a a
3 ./box eco a
./box info
./box ll
6 ./box ejecuta
./box ejecuta ls -i
#include <stdio.h>
2 #include <unistd.h>
#include <errno.h>
#include <stdlib.h>
5 #include <string.h>
int i;
char * c;
c=*argv;
void muestraargs(int argc, char * argv[]) {
23
26
29
32
35 }
8
11
14
17
38
41
44
47
50
53
56 }
for (i=0; i< argc; i++) {
while(*c!=0) {
printf("argv[%d] \t%3d
c++;
}
printf("argv[%d] \t%3d
*c++;
\t %c \n", i, *c, *c);
\t %c \n",i , *c, *c);
}
}
20 void ejecuta(int argc, char * argv[]) {
int i;
char ** v = argv;
v+=2;
for (i=0; i< argc; i++) {
printf("\nargv[%d]: %s\t", i,argv[i]);
}
for (i=0; i< argc-2; i++) {
printf("\nv[%d]: %s\t", i,v[i]);
}
printf("\nResultado: \n");
if (argv[2]==NULL)
printf("Uso: %s ejecuta instruccion\n", argv[0]);
else
execvp(argv[2], v); // execvp
void procesa(int argc, char * argv[]) {
if (strcmp(argv[1],"eco")==0)
printf("%s\n", argv[2]);
else if (strcmp(argv[1],"info")==0)
else if (strcmp(argv[1],"ll")==0) {
execlp("ls","ls","-l",NULL);
printf("\n ############# \n");
perror("no encuentro");
system("uname -a");
// varios parámetros de system (nivel C)
// llamada al sistema execlp
}
else if (strcmp(argv[1],"rm")==0) { // borrar enlaces duros
if (unlink(argv[2]) != 0)
perror("Problema");
}
else if (strcmp(argv[1],"ejecuta")==0)
ejecuta(argc,argv);
else
fprintf(stderr,"Comando incorrecto\n");
5
59 int main(int argc, char * argv[]) {
muestraargs(argc, argv);
if (argc<2) {
printf("Uso: %s instruccion [nombre_de_fichero]\n", argv[0]);
exit(1);
}
else
procesa(argc,argv);
return 0;
Listing 5: Fichero box.c
fork+for
¿Cuántos hijos tiene el programa principal? ¿Qué hace cada hijo? ¿Qué hace el padre?
62
65
68 }
7
10
13
16
19
}
1 #include <stdio.h>
#include <string.h>
#include <unistd.h>
4 #include <stdlib.h>
main () {
int i, x, idh, ret;
for (i=1; i<=5;i++) {
x=fork();
if (x==0) { // hijo
printf("\nSoy el hijo %d\n",i);
sleep(i);
exit(i) ;
}
}
// padre
printf("\nSoy el padre\n");
while ((idh=wait(&ret)) != -1)
printf("\nidh %d \t ret %d",idh,ret/256);
printf("\nFin\n");
Listing 6: Fichero s.c
6
Creación de un intérprete de comandos básico.
Vamos a crear nuestro propio intérprete de comandos.
La primera versión que llamaremos lanzador1 queremos que tenga únicamente la funcionalidad de
ejecutar un programa en modo RUN. Ejecutar un programaX en modo RUN quiere decir que una vez
lanzado el programaX el lanzador1 debe esperar a que el programaX finalice antes de continuar con la tarea
de lanzar otro programa. El lanzador1 termina cuando se detecte fin de fichero en la entrada estándar.
El lanzador1 debe proporcionar las siguientes características propias de los interpretes de comandos:
cada vez que el lanzador1 esté en condiciones de ejecutar un nuevo comando, debe mostrar un prompt al
usuario. En este caso el prompt será “Lanzador1>”
El usuario, una vez que observa el prompt puede introducir un comando. Para ello escribirá en una sola
línea el nombre de programa a ejecutar seguido de sus argumentos ,todos ellos separados por al menos un
blanco o tabulador.
Para realizar el análisis de la línea de comandos dispones de la función ya programada ExtraeArgs().
Esta función se encuentra en el fichero extrae.h
Mejora del lanzador añadiendo el modo de ejecución RUN o SPAWN.
Vamos a mejorar nuestro lanzador1 proporcionándole la posibilidad de ejecutar un comando en modo
RUN o en modo SPAWN . Para ello vamos a modificar la sintaxis de la línea de comandos:
El usuario, una vez que observa el prompt puede introducir un comando. Para ello escribirá en una sola
línea el modo de ejecución R o S , el nombre de programa a ejecutar seguido de sus argumentos, todos ellos
separados por al menos un blanco o tabulador
Ejecutar un programaX en modo RUN quiere decir que una vez lanzado el programaX el lanzador2
debe esperar a que el programaX finalice antes de continuar con la tarea de lanzar otro programa. Ejecutar
un programaX en modo SPAWN quiere decir que el lanzador2 puede pasar a realizar la siguiente tarea sin
esperar a que finalice el programaX.
El lanzador2 termina cuando se detecte fin de fichero en la entrada estándar o cuando el usuario intro-
duzca el comando exit.
En este caso el prompt será “Lanzador2>”
Lanzador2>R cp f1 f2
Lanzador2>S ls
Para implementar lanzador2.c te DEBES utilizar como base el programa lanzador1.c.
Cambio del lanzador añadiendo que se muestre el pid de cada
proceso hijo al término de su ejecución.
Vamos a cambiar nuestro lanzador2 haciendo que se muestre el pid de cada proceso hijo al término de
su ejecución.
En este caso el prompt será “Lanzador3>”
Para implementar lanzador3.c te DEBES utilizar como base el programa lanzador2.c.
7
Cambio del lanzador proporcionando un tiempo máximo de
ejecución a cada comando.
Vamos a cambiar nuestro lanzador3 proporcionando un tiempo máximo de ejecución a cada comando. Si
el programa rebasa el tiempo máximo, se abortara su ejecución y se escribirá el mensaje correspondiente.
El formato de la línea de comandos en este caso será : R o S para indicar el modo de ejecución RUN o
SPAWN, el tiempo máximo de ejecución del programa T= xx y a continuación el programa con todos los
argumentos que necesite.
Por ejemplo.:
Lanzador4>R T= 3 cp f1 f2
Lanzador4>S T= 4 ls
En este caso el prompt será “Lanzador4>”
Para implementar lanzador4.c te DEBES utilizar como base el programa lanzador3.c.
Debes probar este lanzador al menos con los programas pesado y pesado2.
Creación de una función para ejecutar programas.
En la realización de la tarea previa habrás notado que linux no ofrece una función directa para ejecutar
un programa. Sin embargo nos ayudaría de forma notoria el disponer de un función que realice la ejecu-
ción de programas. Otra car
Comentarios de: Actividad 7 - Llamadas al sistema básicas de control de procesos (0)
No hay comentarios