Free Web Site - Free Web Space and Site Hosting - Web Hosting - Internet Store and Ecommerce Solution Provider - High Speed Internet
Search the Web
Implementación de una System Call


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


Problema del triángulo

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.

Cambios en el archivo userprog/syscall.h

:
#define SC_Triangulo     23
:
int Triangulo(int a,int b,int c);
:

Cambios en el archivo userprog/exception.cc

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;

Cambios en el archivo test/start.s

        .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
:
:

Programa procTriangulo.c

#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.

Ir a la página principal