|
|||||||
|
|
|
|||||
|
|
|||||||
Una system call, consiste en estructurar una serie de pasos y respectivas modificaciones de los archivos de NACHOS, con el objetivo de dejar a disposición una funcionalidad del sistema operativo, al igual que las llamadas al sistema que incluye NACHOS por defecto.
Como ejercicio, se propone crear una system call llamada Estad, la cual va a obtener su funcionalidad del método Print( ) , perteneciente a la clase Estatistics, definida en el archivo code/machine/stats.h.
Para ello, se deben seguir los siguientes pasos :
a ) Incluir una constante que identifique a la system call Estad, en el archivo code/userprog/syscall.h, con la constante SC_Estad :
: : #define SC_LockClose 18 #define SC_LockAcquire 19 #define SC_LockRelease 20 #define SC_ThreadExit 21 /* MODIFICACION 28/07/2004 16:09 */ #define SC_Estad 22 #ifndef IN_ASM
Luego, en el mismo archivo, se debe declarar el prototipo de la system call
int LockRelease(LockId id); /* MODIFICACION 28/07/2004 16:10 */ void Estad( ); #endif /* IN_ASM */
Finalmente, se guardan los cambios del archivo userprog/syscall.h.
b) Luego, hay que modificar el archivo code/test/start.s , para incluir las instrucciones en assembler necesarias para ejecución de la ssystem call creada
.globl Halt
.ent Halt
Halt:
addiu $2,$0,SC_Halt
syscall
j $31
.end Halt
/* MODIFICACION 28/07/2004 16:23 */
.globl Estad
.ent Estad
Estad:
addiu $2,$0,SC_Estad
syscall
j $31
.end Estad
.globl Exit
.ent Exit
Exit:
addiu $2,$0,SC_Exit
syscall
j $31
.end Exit
c) Cuando se llama a una syscall, NACHOS invoca a la función ExceptionHandler, implementada en el archivo code/userprog/exception.cc, la cual tiene definida un conjunto de casos, en función de la syscall invocada. En este caso, hay que agregar un caso en donde se especifique la llamada a una función que encapsule las instrucciones, llamada EstadHandler, que realice en forma efectiva la llamada al sistema.
void ExceptionHandler(ExceptionType which)
{
int type = kernel->machine->ReadRegister(2);
int fileID;
int vaddr;
int length;
int returnval;
int childId;
int status;
ASSERT(kernel->currentThread != (Thread*)0);
kernel->currentThread->SaveUserState();
kernel->currentThread->space->SaveState();
ASSERT(kernel->currentThread->space != (AddrSpace*)0);
// default system call return value
returnval = 0;
switch(which) {
case SyscallException:
switch(type) {
case SC_Halt:
DEBUG(dbgSysCall,"System Call: Halt");
kernel->interrupt->Halt();
ASSERT(FALSE);
/* MODIFICACION 28/07/2004 16:36 */
case SC_Estad:
DEBUG(dbgSysCall,"System Call: Estad");
EstadHandler( );
break;
case SC_Exit:
status = kernel->machine->ReadRegister(4);
// we require the status value to be non-negative, since
// negative values are used to indicate errors during Join
// If the status is negative, make it positive.
DEBUG(dbgSysCall,"System Call: Exit status=" << status);
if (status < 0) status *= (-1);
ASSERT(status >= 0);
Terminator(status);
break;
case SC_Exec:
vaddr = kernel->machine->ReadRegister(4);
DEBUG(dbgSysCall,"System Call: Exec vaddr=" << vaddr);
returnval = ExecHandler(vaddr);
break;
:
:
}
d) Luego, hay que implementar en el mismo archivo, la función EstadHandler( ).
:
:
static void
ProcessStartup(int dummy)
{
kernel->currentThread->space->InitRegisters();
kernel->currentThread->space->RestoreState();
kernel->machine->Run();
ASSERT(FALSE);
}
/* MODIFICACION 28/07/2004 16:42 */
// -------------------------------------------------------------------
// EstadHandler
//
// Esta función permite acceder al método Print de la clase Estatistic, a traves
// del objeto kernel->stats
// --------------------------------------------------------------------
void EstadHandler( )
{
kernel->stats->Print( );
}
//----------------------------------------------------------------------
// Terminator
// A helper function to terminate execution of the process that
// calls it.
//
// "status" is the desired exit status for the terminating process
//
// Control never returns from the function
:
:
Como utilizamos la funcion Print( ), declarada en el archivo code/machine/stats.h, hay que realizar el include corespondiente al inicio del archivo :
: : #include "addrspace.h" #include "interrupt.h" /* MODIFICACION 28/07/2004 17:37*/ #include "stats.h" : :
e) Ahora, para probar el funcionamiento de esta nueva system call, crearemos en el directorio code/test el programa llamada01.c.
#include "syscall.h"
int main()
{
Write("ESTADISTICAS DEL SISTEMA\n",25,ConsoleOutId);
Write("------------------------\n",25,ConsoleOutId);
Estad( );
Exit(0);
}
f ) Una vez hecho el programa, debemos modificar el archivo code/test/Makefile para su posterior compilación
:
:
PROGRAMS = halt shell matmult holamundo llamada01 sort segments console_test console_error
file_min file_io exit10 join_test file_error concurrent
endif
:
:
#### INICIO MODIFICACION 28/07/2004 : 17:17 ####
llamada01.o: llamada01.c ../userprog/syscall.h
$(CC) $(CFLAGS) -c llamada01.c
llamada01: llamada01.o start.o
$(LD) $(LDFLAGS) start.o llamada01.o -o llamada01.coff
$(COFF2NOFF) llamada01.coff llamada01
g) Ya que se modificó archivos propios del NACHOS ( code/userprog/syscall.h , code/userprog/exception.cc ), debemos compilarlos, y para ello se debe ejecutar el comando make en el directorio code/build.linux
linux:~/usr/local/nachos/code/build.linux # make g++ -g -Wall -Wno-deprecated -fwritable-strings -I../network -I../filesys -I../userprog -I../threads -I ../machine -I../lib -DRDATA -DSIM_FIX -DFILESYS_STUB -Dx86 -DLINUX -DCHANGED -c ../userprog/exception.cc g++ bitmap.o debug.o libtest.o sysdep.o interrupt.o stats.o timer.o console.o machine.o mipssim.o translate.o network.o disk.o alarm.o kernel.o main.o scheduler.o synch.o thread.o addrspace.o exception.o synchconsole.o proctable.o synchbitmap.o table.o directory.o filehdr.o filesys.o pbitmap.o openfile.o synchdisk.o post.o switch.o -o nachos
*nota : se recomienda antes de hacer el build.linux/make, ejecutar el comando build.linux/make depend.
h) Una vez, realizado la compilacion en el directorio code/buid.linux , debemos hacer la compilación en el directorio code/test, con el comando make.
linux:~/usr/local/nachos/code/test # make
/usr/local/nachos/bin/decstation-ultrix-gcc -G 0 -c -I../userprog -I../lib -I../../dec-include
-I/usr/include -c halt.c /usr/bin/cpp -I../userprog -I../lib -I../../dec-include
-I/usr/include start.s > strt.s /usr/local/nachos/bin/decstation-ultrix-as
-mips2 -o start.o strt.s rm strt.s
:
:
numsections 3
Loading 3 sections:
".text", filepos 0xd0, mempos 0x0, size 0x470
".data", filepos 0x540, mempos 0x480, size 0x0
".bss", filepos 0x0, mempos 0x480, size 0x12c0
/usr/local/nachos/bin/decstation-ultrix-gcc -G 0 -c -I../userprog -I../lib -I../../dec-include
-I/usr/include -c holamundo.c /usr/local/nachos/bin/decstation-ultrix-ld -T script -N start.o
holamundo.o -o holamundo.coff ../../coff2noff/coff2noff.x86Linux holamundo.coff holamundo
numsections 4
Loading 4 sections:
".text", filepos 0xf0, mempos 0x0, size 0x1a0
".rdata", filepos 0x290, mempos 0x200, size 0x10
".data", filepos 0x2a0, mempos 0x280, size 0x0
".bss", filepos 0x0, mempos 0x280, size 0x0
/usr/local/nachos/bin/decstation-ultrix-gcc -G 0 -c -I../userprog -I../lib -I../../dec-include
-I/usr/include -c llamada01.c /usr/local/nachos/bin/decstation-ultrix-ld -T script -N start.o
llamada01.o -o llamada01.coff ../../coff2noff/coff2noff.x86Linux llamada01.coff llamada01
numsections 4
Loading 4 sections:
".text", filepos 0xf0, mempos 0x0, size 0x1b0
".rdata", filepos 0x2a0, mempos 0x200, size 0x40
".data", filepos 0x2e0, mempos 0x280, size 0x0
".bss", filepos 0x0, mempos 0x280, size 0x0
:
:
El siguiente paso es ejecutar nuestro programa llamada01 en el directorio test de la forma :
linux:~/usr/local/nachos/code/test # ./nachos -x llamada01 ESTADISTICAS DEL SISTEMA ------------------------ Ticks: total 2681, idle 1011, system 1640, user 30 Disk I/O: reads 0, writes 0 Console I/O: reads 0, writes 51 Paging: faults 0 Network I/O: packets received 0, sent 0
En el siguiente ejemplo, se mostrará como implementar una system call encargada de procesar, si un triangulo es escaleno, isoceles o equilatero, usando los registros 4,5 y 6 del sistema, como también implementar una nueva opción de debug propia.
PASOS
a) Modificar el archivo debug.h para crear nuestra propia opción de depuración
Para ello, se debe incluir en el archivo code/lib/debug.h la siguiente línea :
const char dbgPropio = 'p'; // debug triangulo
Posteriormente, se puede incluir esta opción en la función DEBUG de la manera DEBUG(dbgPropio,"mensaje")
Para poder activar desde la linea de comando usar : ./nachos -d p -x nombrePrograma
b) Modificar los archivos userprog/syscall.h y userprog/exception.cc y test/start.s para definir la System Call int Triangulo(int a, int b, int c) , que retorna la cantidad de lados iguales.
: #define SC_Triangulo 23 : int Triangulo(int a,int b,int c); :
int TrianguloHandler(int a,int b,int c)
{
int vret = -1;
if (a == b)
{
if (b == c)
vret = 3;
else
vret = 2;
}
else
{
if (b == c)
vret = 2;
else
{
if (c == a)
vret = 2;
else
vret = 0;
}
}
cout << "Lados : " << a << ", " << b << ", " << c << " --> ";
switch(vret)
{
case 0 : cout << "Escaleno\n"; break;
case 2 : cout << "Isoceles\n"; break;
case 3 : cout << "Equilatero\n"; break;
};
DEBUG(dbgPropio,"..DEBUG : Lados iguales : " << vret);
return vret;
}
// --- CASO AGREGADO ----
case SC_Triangulo:
va = kernel->machine->ReadRegister(4);
vb = kernel->machine->ReadRegister(5);
vc = kernel->machine->ReadRegister(6);
returnval = TrianguloHandler(va,vb,vc);
break;
.globl Triangulo
.ent Triangulo
Triangulo:
addiu $2,$0,SC_Triangulo
syscall
j $31
.end Triangulo
Una vez que se cambiaron los archivos propios del sistema, hay que compilarlos con
/build.linux/make depend y luego con build.linux/make.
c) Escribir un programa en el directorio test llamado procTriangulo.c, que reciba el valor de retorno de la llamada al sistema, para contar cuento triangulos hay de cada tipo, mediante una combinatoria de 1 a 3. La particularidad de este programa, consiste en que incluye la librería io_lib.h , que permite usar las funciones : print(char *) y printInt(int).
Para poder enlazar el programa con la librería, se debe incluir la opción en el archivo test/Makefile como se ve a continuación :
:
:
PROGRAMS = halt shell matmult holamundo llamada01 procTriangulo sort segments console_test
console_error file_min file_io exit10 join_test file_error concurrent
:
:
procTriangulo.o: procTriangulo.c io_lib.h ../userprog/syscall.h
$(CC) $(CFLAGS) -c procTriangulo.c
procTriangulo: procTriangulo.o start.o io_lib.h
$(LD) $(LDFLAGS) start.o io_lib.o procTriangulo.o -o procTriangulo.coff
$(COFF2NOFF) procTriangulo.coff procTriangulo
:
:
#include "syscall.h"
#include "io_lib.h"
/* ESTE PROGRAMA HACE UNA COMBINATORIA DE 3 NUMEROS PARA HACER PROCESAR A LA LLAMADA DE SISTEMA Triangulo.
Ademas implementa un contador de tipos de triangulos.
*/
int main( )
{
int numlados = -1;
int contEqui = 0;
int contIso = 0;
int contEsc = 0;
int va = 0;
int vb = 0;
int vc = 0;
Write("\nPrograma del triangulo\n\n",26,ConsoleOutId);
for(va = 1; va <= 3; va++)
for(vb = 1; vb <= 3; vb++)
for(vc = 1; vc <= 3; vc++)
{
numlados = Triangulo(va,vb,vc);
switch(numlados)
{
case 3 : contEqui++; break;
case 2 : contIso++; break;
case 0 : contEsc++; break;
};
}
print("\nTriangulos equilateros : ");
printInt(contEqui);
print("\nTriangulos isoceles : ");
printInt(contIso);
print("\nTriangulos escalenos : ");
printInt(contEsc);
print("\n\nFIN DE PROGRAMA");
Exit(0);
}
d) Una vez escrito el progroma test/procTriangulo.c y haber modificado los archivos test/start.s y test/Makefile , se procece a compilar el directorio con el comando test/make.
e) Compilados los archivos, se hace una prueba con la opción de debug propia p
linux:~/usr/local/nachos/code/test # ./nachos -d p -x procTriangulo Programa del triangulo Lados : 1, 1, 1 --> Equilatero ..DEBUG : Lados iguales : 3 Lados : 1, 1, 2 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 1, 1, 3 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 1, 2, 1 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 1, 2, 2 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 1, 2, 3 --> Escaleno ..DEBUG : Lados iguales : 0 Lados : 1, 3, 1 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 1, 3, 2 --> Escaleno ..DEBUG : Lados iguales : 0 Lados : 1, 3, 3 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 2, 1, 1 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 2, 1, 2 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 2, 1, 3 --> Escaleno ..DEBUG : Lados iguales : 0 Lados : 2, 2, 1 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 2, 2, 2 --> Equilatero ..DEBUG : Lados iguales : 3 Lados : 2, 2, 3 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 2, 3, 1 --> Escaleno ..DEBUG : Lados iguales : 0 Lados : 2, 3, 2 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 2, 3, 3 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 3, 1, 1 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 3, 1, 2 --> Escaleno ..DEBUG : Lados iguales : 0 Lados : 3, 1, 3 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 3, 2, 1 --> Escaleno ..DEBUG : Lados iguales : 0 Lados : 3, 2, 2 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 3, 2, 3 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 3, 3, 1 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 3, 3, 2 --> Isoceles ..DEBUG : Lados iguales : 2 Lados : 3, 3, 3 --> Equilatero ..DEBUG : Lados iguales : 3 Triangulos equilateros : 3 Triangulos isoceles : 18 Triangulos escalenos : 6 FIN DE PROGRAMA
f) Por último, se realiza una ejecución sin la opción de debug
linux:~/usr/local/nachos/code/test # ./nachos -x procTriangulo Programa del triangulo Lados : 1, 1, 1 --> Equilatero Lados : 1, 1, 2 --> Isoceles Lados : 1, 1, 3 --> Isoceles Lados : 1, 2, 1 --> Isoceles Lados : 1, 2, 2 --> Isoceles Lados : 1, 2, 3 --> Escaleno Lados : 1, 3, 1 --> Isoceles Lados : 1, 3, 2 --> Escaleno Lados : 1, 3, 3 --> Isoceles Lados : 2, 1, 1 --> Isoceles Lados : 2, 1, 2 --> Isoceles Lados : 2, 1, 3 --> Escaleno Lados : 2, 2, 1 --> Isoceles Lados : 2, 2, 2 --> Equilatero Lados : 2, 2, 3 --> Isoceles Lados : 2, 3, 1 --> Escaleno Lados : 2, 3, 2 --> Isoceles Lados : 2, 3, 3 --> Isoceles Lados : 3, 1, 1 --> Isoceles Lados : 3, 1, 2 --> Escaleno Lados : 3, 1, 3 --> Isoceles Lados : 3, 2, 1 --> Escaleno Lados : 3, 2, 2 --> Isoceles Lados : 3, 2, 3 --> Isoceles Lados : 3, 3, 1 --> Isoceles Lados : 3, 3, 2 --> Isoceles Lados : 3, 3, 3 --> Equilatero Triangulos equilateros : 3 Triangulos isoceles : 18 Triangulos escalenos : 6 FIN DE PROGRAMA
*nota : en caso de que después de compilar, los cambios no se hacen efectivos, tratar con hacer un make clean en los directorios test/build.linux y code/test además de eliminar el archivo build.linux/nachos (usar comando rm), para luego compilar todo de nuevo.