next up previous contents
Next: Simulación del video CGA Up: La aplicación VM Previous: Objetos principales de la

Ejecución de la aplicación VM

La aplicación VM se ha desarrollado para ejecutar programas 8086 con formato COM. Cuando se ejecuta la aplicación VM, NeXTSTEP crea el objeto NXApp, lo pone a ejecutar y se muestra la interfaz de usuario de la aplición.

Cuando se carga un programa 8086, el hilo GUI ejecuta el método openDocument. Al ejecutar este método se crea un objeto de la clase VirtualMode (donde se controlará al hilo V86, y desplegará la información que mande el monitor).

- openDocument:sender
{
    char *types[2] = {"com", 0};
    
   if ( [[OpenPanel new] runModalForTypes:types])  
       nombrearchivo = (char *)[[OpenPanel new] filename]; 

    currentVM = [[VirtualMode alloc] init];
    [currentVM show:self];
    [currentVM carga:nombrearchivo];
    
    return self;
}
Después de abrir el panel de archivos y seleccionar un nombre, se le envía el mensaje carga al objeto de la clase VirtualMode, para que el programa 8086 se carge en el área de memoria de la tarea V68.

Cuando se inicializa el objeto VirtualMode, esto es, cuando se le envía el mensaje init. Habilita el entorno donde tomará los archivos, inicializa algunas variables de instancia, crea el puerto donde los hilos monitor y memoria se comunicarán con el hilo GUI (y le asocia una función que maneja el mensaje: msHandler()), y manda a ejecutar a la funcion tarea_monitor(), la cual se encarga de crear una tarea Mach con un megabyte de memoria disponible a partir de la dirección cero:

- init
{
   [super init];
   port_allocate(task_self(), &guiPort);
   DPSAddPort(guiPort, msgHandler, sizeof(simpleMsg), self, 
               NX_MODALRESPTHRESHOLD +1);
   ....

   tarea_monitor();
   ... 

   return self;
}

Cuando al objeto de la clase VirtualMode se le manda el mensaje carga, activa un hilo de ejecución que se encarga de escribir el programa 8086 a la tarea virtual, mientras el hilo GUI atiende el mensaje (del hilo cargaArchivo), para desplegar el archivo desensamblado en la interfaz de usuario.

- carga:(char *)nombrearchivo
{
   id cargaArchivo; 

   cargaArchivo = [[ThreadEngine alloc] init]; 
   [cargaArchivo fork:(cthread_fn_t)carga arg: 
                  (any_t)nombrearchivo]; 
   [buttonExe setEnabled:YES]; 
   [threadState setStringValue: nombrearchivo]; 
   [myWindow setTitle: nombrearchivo];
   [myWindow makeKeyAndOrderFront:nil];

   return self; 
}

Después de crear la tarea V86, y cargar y desplegar el programa 8086, espera a que el usuario le envie el mensaje execute --generado por el evento de presionar el botón del ratón sobre el botón em Exe/Stop--. Cuando el objeto de la clase VirtualMode recibe este mensaje, se crea el hilo monitor7.2 y le manda a ejecutar la función maneja_hiloV86, la cual se encarga de crear e inicializar al hilo virtual v86. Después crea el hilo memoria7.3, y se le manda ejecutar la función memoriaV86, la cual envia cada 5 segundos información del estado de la memoria de la tarea V86 al hilo GUI para que se despliegue. Finalmente, una vez que se han creado y puesto a funcionar los hilos monitor y memoria, se manda a ejecutar al hilo V86.

- execute:sender
{
   if (monitor == nil) { 
      monitor = [[ThreadEngine alloc] init]; 
      [monitor fork:(cthread_fn_t)maneja_hiloV86 arg:(any_t)0]; 

      memoria = [[ThreadEngine alloc] init]; 
      [memoria fork:(cthread_fn_t)memoriaV86 arg:(any_t) 0]; 
   } else { 
      /* codigo para desactivar las ejecuciones del hilo
       * virtual, del hilo monitor, y del hilo de memoria 
       */
      [self endExecute];
   }

   return self;
}
En este listado se muestra que la ejecución del método puede variar, dependiendo del valor de la variable monitor. Debido a que el botón que manda el mensaje es Exe/Stop, cuando se envía nuevamente el mensaje se verifica si existe el objeto monitor, como ya se ha creado, entonces se supone que se desea terminar la ejecución del hilo V86 y se manda a ejecutar el método endExecute para este propósito.

Los elementos que se ejecutan en modo protegido dentro de la aplicación son el hilo GUI, el objeto memoria y el objeto monitor. Estos elementos ejecutables se comunican entre sí, a través de mensajes. Los objetos monitor y memoria se comunican con la tarea V86 compartiendo el área de memoria de la tarea V86, ver figura 7.3.

  
Figure 7.3: Comunicación entre los hilo de ejecución de la aplicación VM.
\begin{figure}
\epsfxsize=220pt
\hspace{.02in}
\epsffile{comunicVM.eps}
\end{figure}

Cuando se esta ejecutando el proceso V86, el hilo GUI espera a que el hilo monitor y el hilo de memoria le envíen mensajes que se mostrarán en interfaz gráfica. Para realizar esta comunicación entre los hilos monitor y memoria (y al inicio con el hilo cargaArchivo), los hilos mandan envian un mensaje al puerto asociado al hilo GUI, y el hilo GUI ejecuta la función que se encarga de manejar los mensajes: msgHandler(). Esta función, manda a ejecutar el método draw, que se encarga de desplegar los mensajes en los distintos objetos gráficos.

static void msgHandler(msg, self)
simpleMsg *msg;
id self;
{
    [self draw:msg];
}
El método draw, verifica el cuerpo del mensaje , y dependiendo del identificador asociado al mensaje, el hilo GUI manda mensajes de despliegue a los distintos objetos gráficos:
- draw:(simpleMsg *)msg
{
    ...
    switch(msg->h.msg_id) {
    case STATE_MSG: ... 
    case EXCEP_MSG: ... 
    case CLEAR_MSG: ... 
    case MEMOR_MSG: ...
    case PROGR_MSG: ... 
    case NLOAD_MSG: ...
    case SIMVI_MSG: ...
    }
    return self;
}
En esta lista se observan diferentes tipo de identificadores que corresponden a:
STATE_MSG
Este mensaje indica que se está enviando el estado del hilo V86, y debe desplegarse.

EXCEP_MSG
Este mensaje indica que se está enviando un mensaje de que a ocurrido una excepción y se enciende en la barra de excepciones la instrucción que la ha causado.

MEMOR_MSG
Este mensaje indica que lo envía el hilo memoria y manda el contenido de una parte de la memoria de la tarea V86 que debe desplegarse en la interfaz gráfica del usuario.
CLEAR_MSG
Este mensaje lo envía el hilo memoria e indica que debe borrarse el área de video donde se está desplegando la memoria de la tarea V86.

PROGR_MSG
Este mensaje se envía para indicar que tiene código 8086 desensamblado y debe mostrarse en la interfaz gráfica de usuario.

NLOAD_MSG
Este mensaje indica que hubo un problema al momento de cargar un programa 8086 a la tarea V867.4, se debe mostrar un panel de alerta.

SIMVI_MSG
Este mensaje indica que se debe realizar una simulación del video CGA.

El hilo de memoria se activa cada determinado tiempo y se encarga de leer una región de la memoria de la tarea V86 y la envía al hilo GUI para que se muestre al usuario:

void memoriaV86()
{
   simpleMsg  mensaje; 
   init_msg(&mensaje); 
   while(1) { 
     mensaje.h.msg_id = MEMORY_MSG; 
     obten_memoria(&new_t, (vm_address_t) addr, 16, 
                    mensaje.body);
     msg_send((msg_header_t *)&mensaje,MSG_OPTION_NONE,0);
     sleep(5); 
     if (addr<addrL) addr+=16; 
     else { 
        addr = (char *)PAGINA_VIRTUAL; 
        mensaje.h.msg_id = CLEAR_MSG; 
        msg_send((msg_header_t *)&mensaje,
                  MSG_OPTION_NONE,0);
        sleep(5); 
     }
   }
}

El hilo V86 y el objeto monitor se comunican para el manejo de excepciones. Cuando el objeto monitor procesa una excepción envía el tipo de excepción y el estado del hilo V86 al objeto GUI para que se muestre al usuario. Esta comunicación la hace el hilo monitor desde la función que maneja la excepción que simula las instrucciones privilegiadas do_bad_instruction:

void do_bad_instruction(u_char *eip, i386_thread_state_t *state)
{
   simpleMsg  mensaje; 
   init_msg(&mensaje); 

   switch(*eip) {
   case I386_INT:
           if (stopException==YES) {
              mensaje.h.msg_id = EXCEPTION_MSG; 
              mensaje.body[0] =(char) *eip; 
              mensaje.body[1] = mensaje.body[2] 
                              = mensaje.body[3] = '\0'; 
              msg_send((msg_header_t *)&mensaje,
                         MSG_OPTION_NONE,0);
              mutex_lock(ExcLock);
              while(!bandera)
                condition_wait(ExcUpdated,ExcLock);
              mutex_unlock(ExcLock);
              bandera = 0; 
           }
           do_int(eip, state); 
           break;  
    ... 
  }
}
El hilo monitor se queda esperando hasta el que hilo GUI encienda la bandera para que pueda reanudar su ejecución (esto ocurre cuando el usuario oprime el botón Continue).

Cuando el hilo monitor detecta que la excepción atrapada corresponde al servicio de video de BIOS (INT 0x10), le manda un mensaje al objeto CGAView con el estado del hilo V86, y despues envia un mensaje IPC al hilo GUI para despliegue el resultado de la simulación.

void do_int10_bios(i386_thread_state_t *st)	
{
    simpleMsg  mensaje; 
    init_msg(&mensaje); 

    state=st; 
    *banderaVideo=1; 
    mensaje.h.msg_id = SIMULAVIDEO_MSG; 
    mensaje.body[0] ='\0'; 
    mensaje.body[1] = mensaje.body[2] = mensaje.body[3] = '\0'; 
    msg_send((msg_header_t *)&mensaje,MSG_OPTION_NONE,0);
    while(*banderaVideo!=0) ;  
}
El estado del hilo se manda a la variable compartida state, entre el hilo monitor y el hilo GUI. Cuando el hilo GUI verifica que el mensaje corresponde a la simulación del video CGA, dependiendo de los valores de la variable state manda mensajes al objeto videoCGA para realizar la simulación correspondiente. El hilo monitor espera a que la simulación ocurra para continuar su ejecución.


next up previous contents
Next: Simulación del video CGA Up: La aplicación VM Previous: Objetos principales de la
Amilcar Meneses
2002-10-03