/*
 * SITR, practica 1
 * Archivo: invprio.C
 *     Comprobacion de gestion de colas por prioridad
 * 
 * Se utiliza un servidor (servidorA), que proporciona un unico servicio:
 * realizar espera ocupada el numero de veces que se incluye en el mensaje.
 *
 * Se utilizan tambien tres clientes (clienteA, clienteB y clienteC) con
 * prioridades 200, 215 y 230, respectivamente. Los clientes depositan sus
 * peticiones en el orden C, B, A. Las peticiones se distinguen por la
 * duracion de la espera ocupada (5 para A, 10 para B y 15 para C).
 *
 * De esta forma es posible observar en que orden procesa las peticiones
 * el servidor, y asi comprobar que se respetan las prioridades.
 */

#include "kmospub.h"               /* declaraciones de servicios KMOS     */
#include <dos.h>                   /* inclusion para llamadas a  DOS/BIOS */
#include <string.h>                /* ... para manipulacion de cadenas    */
#include <stdio.h>                 /* ... para sprintf */
#include <alloc.h>                 /* ... para asignacion de memoria      */

palabra _stklen = 128*1024;        /* definir tamaño de pila              */

#define true 1                     /* valor lógico cierto                 */
#define cip01 0x21                 /* control int. progr. PC, reg ordenes */
#define tecla_y_disco 0xbd         /* cte. habilita ints TECLADO y DISCO  */
#define imprcadena 9               /* no. servicio DOS imprimir cadenas   */
#define byte unsigned char         /* define byte como unsigned char      */

/* INTOFF y INTON: procedimientos identicos a los homonimos en KMOS  */
#define inton asm sti                  /* STI, permitir interrupciones    */
#define intoff asm cli                 /* CLI, prohibir interrupciones    */

/*
 * Funciones auxiliares
 */

/*
 * imprime()
 *    imprime la cadena que se le pasa como argumento
 *
 * Entrada: cadena (debe terminar en '$')
 */
void
imprime(char *cad)
{
    byte salvamascara;
    union REGS regspp;                 /* estructuras DOS.H para acceso a regs*/
    struct SREGS sregspp;


    regspp.h.ah = 9;                 /* DOS/BIOS INT 21/9 = imprimir    */
    regspp.x.dx = FP_OFF(cad);       /* ds:dx apunta a la cadena  */
    sregspp.ds = FP_SEG(cad);

    salvamascara = inportb(cip01);   /* manipulacion de CIP para        */
    outportb(cip01, tecla_y_disco);  /*deshabilitar ints dentro de BIOS */
    intdosx(&regspp, &regspp, &sregspp); /* llamada al BIOS             */
    outportb(cip01, salvamascara);   /* restaurar mascar/interr. CIP    */
}
   
/*
 * espera_ocupada()
 *     mantiene ocupado el procesador
 *
 * Entrada: duracion de la espera, cadena a mostrar en cada iteracion
 */
void
espera_ocupada(int t, char *cad)
{
    unsigned long x, y;

    while (t--) {
      for (x=0x100; x; --x)
        for (y=0xFFFF; y; --y);
      imprime(cad);
    }
}
   
/*
 * Funciones base para los procesos que se utilizan
 */

/* las direcciones (identificadores) de los servidores */
void *dir_SA = NULL;
                
/*
 * Proceso servidor A
 */
void 
servidorA()
{
    unsigned int cnt=3;		  /* Cuenta */
    char cad[128];              /* Cadena a imprimir */
    unsigned n;                 /* buf. de destino para los mensajes */
    unsigned nrec;              /* Num. de bytes recibidos */

    imprime("SA - Activado\r\n$");
    k_retardar(40);
    while (cnt--)
    {
        imprime("SA - esperando cliente...\r\n$");
        nrec = k_cola_recibir(&n, sizeof(n));
                        
        /* el servidor proporciona una sola operación:
         * n ciclos de espera ocupada, donde n está incluido en el mensaje */
        intoff;
        sprintf(cad, 
                "SA - recibidos %u bytes: "
                "operación = esperar %u veces\r\n$",
                nrec, n);
        inton;
        imprime(cad);

        /* llevar a cabo la operación solicitada */
        espera_ocupada(n, "SA  $");
    }
    k_terminar(0);
}

/*
 * Procesos cliente
 */
void 
clienteA()    
{                            
    unsigned nespera = 5;

    imprime("CA - Activado\r\n$");
    k_retardar(25);
    while (1)
    {
        imprime("CA - enviando petición a SA...\r\n$");
        k_cola_enviar(dir_SA, &nespera, sizeof(nespera));
        imprime("CA - petición enviada\r\n$");

        k_retardar(1000);
    }
}

void 
clienteB()                    
{                            
    unsigned nespera = 10;

    imprime("CB - Activado\r\n$");
    k_retardar(20);
    while (1)
    {
        imprime("CB - enviando petición a SA...\r\n$");
        k_cola_enviar(dir_SA, &nespera, sizeof(nespera));
        imprime("CB - petición enviada\r\n$");

        k_retardar(1000);
    }
}

void 
clienteC()             
{                            
    unsigned nespera = 15;

    imprime("CC - Activado\r\n$");
    k_retardar(15);
    while (1)
    {
        imprime("CC - enviando petición a SA...\r\n$");
        k_cola_enviar(dir_SA, &nespera, sizeof(nespera));
        imprime("CC - petición enviada\r\n$");

        k_retardar(1000);
    }
}
                       
/*
 * Funcion principal
 */
void main()
{
   kmosinicial();                      /* inicializar KMOS             */

   /* Crear procesos de usuario */
   dir_SA = k_crearproc(servidorA, "SA", 1024, 250);
   (void) k_crearproc(clienteA, "CA", 256, 200);
   (void) k_crearproc(clienteB, "CB", 256, 215);
   (void) k_crearproc(clienteC, "CC", 256, 230);

   if ( sbrk(64*1024) == NULL ) return;/* conseguir suficiente mem. din. */
   kmosiniciar();                      /* iniciar el sistema operativo */
}
