Subversion Repositories shark

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

/*
 * Project: S.Ha.R.K.
 *
 * Coordinators:
 *   Giorgio Buttazzo    <giorgio@sssup.it>
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *
 * Authors     :
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *   Massimiliano Giorgi <massy@gandalf.sssup.it>
 *   Luca Abeni          <luca@gandalf.sssup.it>
 *   (see the web pages for full authors list)
 *
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
 *
 * http://www.sssup.it
 * http://retis.sssup.it
 * http://shark.sssup.it
 */


/**
 ------------
 CVS :        $Id: hartport.c,v 1.1.1.1 2002-03-29 14:12:52 pj Exp $

 File:        $File$
 Revision:    $Revision: 1.1.1.1 $
 Last update: $Date: 2002-03-29 14:12:52 $
 ------------

 This file contains the Hartik 3.3.1 Port functions

 Author:      Giuseppe Lipari
 Date:        2/7/96

 File:  Port.C (renamed to hartport.c)
 Revision:    1.4

**/


/*
 * Copyright (C) 2000 Paolo Gai
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */



#include <modules/hartport.h>
#include <kernel/config.h>
#include <ll/ll.h>
#include <ll/string.h>
#include <ll/stdio.h>
#include <kernel/model.h>
#include <kernel/const.h>
#include <sys/types.h>
#include <kernel/descr.h>
#include <errno.h>
#include <kernel/var.h>
#include <kernel/func.h>


static sem_t hash_mutex;

#define __PORT_DBG__

struct hash_port {
        char    name[MAX_PORT_NAME];
        PID     port_index;
        BYTE    blocked;
        sem_t   sem;
        BYTE    valid;
        int     port_int;
};

struct port_ker {
        BYTE    valid;
        int     next;
        WORD    dim_block;
        BYTE    *mem_block;
        BYTE    *head;
        BYTE    *tail;
        BYTE    type;
        sem_t   mutex;
        sem_t   pieno;
        sem_t   vuoto;
};

struct port_com {
        BYTE    valid;
        int     next;
        PID     proc_id;
        BYTE    access;
        int     port_index;
        WORD    dim_mes;
        int     h_index;
};
       
struct hash_port        htable[MAX_HASH_ENTRY];
struct port_ker         port_des[MAX_PORT];
struct port_com         port_int[MAX_PORT_INT];
QUEUE   freeportdes;
QUEUE   freeportint;

static int port_installed = 0;

 
/*----------------------------------------------------------------------*/
/* port_init() : inizializza le strutture delle porte; da chiamare      */
/* dentro __hartik_register_levels__().                                 */
/*----------------------------------------------------------------------*/
void HARTPORT_init(void)
{
    int i;

    if (port_installed)
      return;
    port_installed = 1;

    /* Init hash table                  */
    for (i = 0; i < MAX_HASH_ENTRY; i++) {
        htable[i].valid = FALSE;
        htable[i].port_int = NIL;
        htable[i].blocked = 0;
    }

    /* mutex sem on the hash table              */
    sem_init(&hash_mutex, 0, 1);

    /* init the port descriptor table   */
    for (i = 0; i < MAX_PORT - 1; i++) {
        port_des[i].next = i+1;
        port_des[i].valid = FALSE;
    }
    port_des[MAX_PORT - 1].next = NIL;
    port_des[MAX_PORT - 1].valid = FALSE;
    freeportdes = 0;

    /* Init the port interface table    */
    for (i = 0; i < MAX_PORT_INT - 1; i++) {
        port_int[i].next = i+1;
        port_int[i].valid = FALSE;
    }
    port_int[MAX_PORT_INT - 1].next = NIL;
    port_int[MAX_PORT_INT - 1].valid = FALSE;
//    for (i = PORT_NO_MORE_DESCR; i <= PORT_UNVALID_DESCR; i++)
//        exc_set(i,port_exception);
    freeportint = 0;
}


/*----------------------------------------------------------------------*/
/* hash_fun() : address hash table                                      */
/*----------------------------------------------------------------------*/
static int hash_fun(char *name)
{
    return (*name % MAX_HASH_ENTRY);
}


/*----------------------------------------------------------------------*/
/* getfreedes : restituisce l'indice di un descrittore di porta libero  */
/*----------------------------------------------------------------------*/
static int getfreedes(void)
{
    int p;

    kern_cli();
    if (freeportdes == NIL) {
        errno = EPORT_NO_MORE_DESCR;
        kern_sti();
        return -1;
    }
    p = freeportdes;
    freeportdes = port_des[p].next;
    kern_sti();
    return(p);
}        

/*----------------------------------------------------------------------*/
/* ungetdes() : mette il descrittore tra quelli disponibile             */
/*----------------------------------------------------------------------*/
static void ungetdes(int pd)
{
    kern_cli();
    port_des[pd].next = freeportdes;
    freeportdes = pd;
    kern_sti();
}

/*----------------------------------------------------------------------*/
/* get freeint : restituisce una interfaccia di porta libera            */
/*----------------------------------------------------------------------*/
static int getfreeint(void)
{
    int p;

    kern_cli();
    if (freeportint == NIL) {
        errno = EPORT_NO_MORE_INTERF;
        kern_sti();
        return -1;
    }
    p = freeportint;
    freeportint = port_int[p].next;
    kern_sti();
    return(p);
}      

/*----------------------------------------------------------------------*/
/* ungetint : rende disponibile l'interfaccia di porta specificata      */
/*----------------------------------------------------------------------*/
static void ungetint(int pi)
{
    kern_cli();
    port_int[pi].next = freeportint;
    freeportint = pi;
    kern_sti();
}

/*----------------------------------------------------------------------*/
/* port_create(): Apre la porta specificata dalla stringa, effettuando  */
/* automaticamente il collegamento                                      */
/* WARNING : La funzione e' bloccante per la mutua esclusione sulla     */
/* hash table                                                   */
/*----------------------------------------------------------------------*/
PORT port_create(char *name, int dim_mes, int num_mes, BYTE type, BYTE access)
{
    int i, pd, pi;
    WORD letti = 0;
    BYTE flag = FALSE;

/*
   Prendo un descrittore di porta.
*/

    #ifdef __PORT_DBG__
        if ((type == MAILBOX) && (access == WRITE)) {
           errno = EPORT_INCOMPAT_MESSAGE;
           return -1;
        }
        if ((type == STICK  ) && (access == READ )) {
           errno = EPORT_INCOMPAT_MESSAGE;
           return -1;
        }
    #endif
    pd = getfreedes();
    if (pd == -1) return -1;
/*
   Devo andare in mutua esclusione sulla tabella di hash ! Poiche' questa
   viene acceduta dalle openport e dalle connect sono sicuro che una
   connect non puo' interrompere una openport.
*/

    sem_wait(&hash_mutex);
/*
   Scorro la tabella di hash fino a trovare un'entrata libera, oppure
   una entrata occupata in precedenza da una connect che ci si e' bloccata
   sopra (blocked > 0). Se ne trovo una gia' aperta da un'altra openport
   esco con errore. Lo stesso se sono state occupate tutte le entrate della
   tabella (tramite la var. letti);
*/

    i = hash_fun(name);
    while (!flag) {
        if (htable[i].valid == FALSE) flag = TRUE;
        else {
            if (strcmp(htable[i].name,name) == 0) {
                if (htable[i].blocked == 0) {
                    errno = EPORT_ALREADY_OPEN;
                    sem_post(&hash_mutex);
                    return -1;
                }
                else flag = TRUE;
            }
            else {
                i = (i+1) % MAX_HASH_ENTRY;
                letti++;
            }
        }
        if (letti > MAX_HASH_ENTRY-1) {
            errno = EPORT_NO_MORE_HASHENTRY;
            sem_post(&hash_mutex);
            return -1;
        }

    }
    htable[i].valid = TRUE;
    strcpy(htable[i].name, name);

    htable[i].port_index = pd;
/*
   A questo punto inizializzo tutta la struttura del descrittore di porta
*/

    if (type == STICK)  port_des[pd].dim_block = dim_mes;
    else port_des[pd].dim_block = dim_mes * num_mes;

    kern_cli();
    port_des[pd].mem_block = kern_alloc(port_des[pd].dim_block);
    kern_sti();
    if (port_des[pd].mem_block == NULL) {
        errno = EPORT_2_CONNECT;
        sem_post(&hash_mutex);
        return -1;
    }

    port_des[pd].head = port_des[pd].tail = port_des[pd].mem_block;

    sem_init(&port_des[pd].mutex,0,1);
    sem_init(&port_des[pd].pieno,0,port_des[pd].dim_block);
    sem_init(&port_des[pd].vuoto,0,0);
    port_des[pd].type = type;
/*
   Prendo e inizializzo la struttura dell'interfaccia di porta verso il
   processo (e' la varibile pi quella che restituisco)
*/

    pi = getfreeint();
    if (pi == -1) {
        sem_post(&hash_mutex);
        return -1;
    }
       
/*  port_int[pi].proc_id = exec_shadow; */
    port_int[pi].access = access;
    port_int[pi].port_index = pd;
    port_int[pi].dim_mes = dim_mes;
    port_int[pi].next = NIL;
    port_int[pi].h_index = i;
    port_des[pd].valid = TRUE;
    port_int[pi].valid = TRUE;
/*
   Sblocco eventuali processi che avevano fatto la connect nella coda
   semaforica che sta nell'entrata relativa della hash table !
*/

    if (htable[i].blocked > 0) {
        sem_xpost(&htable[i].sem, htable[i].blocked);
        htable[i].blocked = 0;
        sem_destroy(&htable[i].sem);
    }
/*
   Infine libero la mutua esclusione.
*/

    sem_post(&hash_mutex);
    return (pi);
}

/*----------------------------------------------------------------------*/
/* port_connect(): collega la porta specificata dalla stringa.          */
/* WARNING : La funzione e' bloccante per la mutua esclusione sulle     */
/* strutture delle porte                                                */
/*----------------------------------------------------------------------*/
PORT port_connect(char *name, int dim_mes, BYTE type, BYTE access)
{
    int i, pi, pd, pn,letti = 0;
    BYTE flag = FALSE, create = FALSE;

    #ifdef __PORT_DBG__
        if ((type == MAILBOX) && (access == READ )) {
            errno = EPORT_INCOMPAT_MESSAGE;
            return -1;
        }
        if ((type == STICK  ) && (access == WRITE)) {
           errno = EPORT_INCOMPAT_MESSAGE;
           return -1;
        }
    #endif
/*
   Per prima cosa mi prendo una interfaccia di porta e la riempio
   parzialmente.       
*/

    pi = getfreeint();
    if (pi == -1) return -1;
/*  port_int[pi].proc_id = exec_shadow; */
    port_int[pi].access = access;
    port_int[pi].dim_mes = dim_mes;
    port_int[pi].next = NIL;
/*
   Mutua esclusione sulla tabella di hash
*/

    sem_wait(&hash_mutex);
/*
   Cerco il descrittore appropriato : Se la porta e' gia' stata aperta
   allora esco dal ciclo con flag = TRUE, create = FALSE, l'indice i che
   punta all'entrata della tabella di hash, e con htable[i].blocked = 0;
   In tutti gli altri casi significa che la porta non e' stata aperta e
   quindi devo bloccarmi.
*/

    i = hash_fun(name);
    while (!flag) {
        /* Devo crearla */
        if (htable[i].valid == FALSE) {
            flag = TRUE;
            create = TRUE;
        }
        /* l'ho trovata (ma non so ancora se e' stata aperta) */
        else if (strcmp(htable[i].name, name) == 0) flag = TRUE;
        /* scandisco l'entrata successiva */
        else {
            i = (i+1) % MAX_HASH_ENTRY;
            letti ++;
        }
        #ifdef __PORT_DBG__
            /* se ho scorso tutto l'array senza trovare nulla */
            if (letti > MAX_HASH_ENTRY) {
                errno = EPORT_NO_MORE_HASHENTRY;
                sem_post(&hash_mutex);
                return -1;
            }
        #endif
    }
       
/*
   Se devo aspettare che venga aperta (create = TRUE) allora mi blocco in
   attesa sul semaforo della htable. Per non avere troppi semafori inutili
   in giro, me lo creo sul momento.
*/

    if (create == TRUE) {
        htable[i].valid = TRUE;
        htable[i].blocked = 1;
        strcpy(htable[i].name, name);
        sem_init(&htable[i].sem, 0, 0);
        sem_post(&hash_mutex);
        sem_xwait(&htable[i].sem,1,BLOCK);
    }
/*
   Se invece si e' gia' bloccata un'altra connect sopra, mi blocco anch'io.
   in ogni caso devo liberare la mutua esclusione sulla hash dato che ho
   gia' fatto tutto quello che dovevo fare con la hash.
*/

    else {
        if (htable[i].blocked > 0) {
            htable[i].blocked++;
            sem_post(&hash_mutex);
            sem_xwait(&htable[i].sem,1,BLOCK);
        }
        else sem_post(&hash_mutex);
    }
/*
   Controlli di errore.
*/

    pd = htable[i].port_index;
    #ifdef __PORT_DBG__
        if (type != port_des[pd].type) {
            errno = EPORT_UNSUPPORTED_ACC;
            return -1;
        }
        if ((type == STICK) && (dim_mes != port_des[pd].dim_block)) {
            errno = EPORT_WRONG_OP;
            return -1;
        }
        if ((type != STICK) && (port_des[pd].dim_block % dim_mes) != 0) {
            errno = EPORT_WRONG_OP;
            return -1;
        }
    #endif

    sem_wait(&hash_mutex);
    pn = htable[i].port_int;
    if (pn != NIL) {
        #ifdef __PORT_DBG__
            if (type == STREAM) {
                errno = EPORT_WRONG_TYPE;
                sem_post(&hash_mutex);
                return -1;
            }
            if (dim_mes != port_int[pn].dim_mes) {
                errno = EPORT_WRONG_OP;
                sem_post(&hash_mutex);
                return -1;
            }
        #endif
        port_int[pi].next = htable[i].port_int;
        htable[i].port_int = pi;
    }
    else htable[i].port_int = pi;
    sem_post(&hash_mutex);
    port_int[pi].h_index = i;
    port_int[pi].port_index = pd;
    port_int[pi].valid = TRUE;
    return(pi);
}

/*----------------------------------------------------------------------*/
/* port_delete() : inversa di port_open, libera tutto                   */
/*----------------------------------------------------------------------*/
void port_delete(PORT pi)
{
    int i;
    struct port_ker *pd;
    struct port_com *pp;

    pp = &port_int[pi];
    sem_wait(&hash_mutex);
    i = pp->h_index;
    pd = &port_des[htable[i].port_index];
    pd->valid = FALSE;
    sem_destroy(&pd->mutex);
    sem_destroy(&pd->pieno);
    sem_destroy(&pd->vuoto);
   
    kern_cli();
    kern_free(pd->mem_block, pd->dim_block);
    kern_sti();

    ungetdes(htable[i].port_index);
    pp->valid = FALSE;
    htable[i].port_int = pp->next;
    ungetint(pi);
    htable[i].valid = FALSE;
    sem_post(&hash_mutex);
}

/*----------------------------------------------------------------------*/
/* port_disconnect() : libera l'interfaccia di porta                    */
/*----------------------------------------------------------------------*/
void port_disconnect(PORT pi)
{
    sem_wait(&hash_mutex);
    if (htable[port_int[pi].h_index].valid == TRUE)
        htable[port_int[pi].h_index].port_int = port_int[pi].next;
    port_int[pi].valid = FALSE;
    ungetint(pi);
    sem_post(&hash_mutex);
}

/*----------------------------------------------------------------------*/
/* port_send() : Invia un messaggio alla porta                          */
/*----------------------------------------------------------------------*/
WORD port_send(PORT pi, void *msg, BYTE wait)
{
    struct port_ker *pd;
    struct port_com *pp;

    pp = &(port_int[pi]);
    pd = &(port_des[pp->port_index]);
       
    #ifdef __PORT_DBG__
        if (pp->access == READ) {
          errno = EPORT_WRONG_OP;
          return -1;
        }
        if (!pd->valid) {
          errno = EPORT_UNVALID_DESCR;
          return -1;
        }

    #endif

    if (pd->type == STICK) sem_wait(&pd->mutex);
    else if (pd->type == STREAM) {
            if (sem_xwait(&pd->pieno,pp->dim_mes,wait)) return(FALSE);
    }
    else {
        if (sem_xwait(&pd->pieno, pp->dim_mes,wait)) return(FALSE);
        sem_wait(&pd->mutex);
    }

    memcpy(pd->head, msg, pp->dim_mes);

    pd->head += pp->dim_mes;
   
    if (pd->head >= (pd->mem_block + pd->dim_block))
        pd->head -= pd->dim_block;

    if (pd->type == STICK) sem_post(&pd->mutex);
    else if (pd->type == STREAM) sem_xpost(&pd->vuoto, pp->dim_mes);
    else {
        sem_xpost(&pd->vuoto, pp->dim_mes);
        sem_post(&pd->mutex);
    }
    return(TRUE);
}

/*----------------------------------------------------------------------*/
/* port_receive() : Riceve un messaggio dalla porta                     */
/*----------------------------------------------------------------------*/
WORD port_receive(PORT pi,void *msg,BYTE wait)
{
    struct port_ker *pd;
    struct port_com *pp;

    pp = &(port_int[pi]);
    pd = &(port_des[pp->port_index]);
       
    #ifdef __PORT_DBG__
        if (pp->access == WRITE) {
          errno = EPORT_WRONG_OP;
          return -1;
        }
        if (!pd->valid) {
          errno = EPORT_UNVALID_DESCR;
          return -1;
        }
    #endif     

    if (pd->type == STICK) sem_wait(&pd->mutex);
    else if (pd->type == STREAM) {
         if (sem_xwait(&pd->vuoto,pp->dim_mes,wait)) return(FALSE);
    }
    else {
        if (sem_xwait(&pd->vuoto,pp->dim_mes,wait)) return(FALSE);
        sem_wait(&pd->mutex);
    }

    memcpy(msg, pd->tail, pp->dim_mes);

    pd->tail += pp->dim_mes;
    if (pd->tail >= (pd->mem_block + pd->dim_block))
        pd->tail -= pd->dim_block;

    if (pd->type == STICK) sem_post(&pd->mutex);
    else if (pd->type == STREAM) sem_xpost(&pd->pieno, pp->dim_mes);
    else {
        sem_xpost(&pd->pieno, pp->dim_mes);
        sem_post(&pd->mutex);
    }
    return(TRUE);
}

#ifdef __PORT_DBG__

void print_port(void)
{
    int i;
    struct port_ker *pd;
    struct port_com *pp;
       
/*
        kern_printf("Hash Table :\n");
        for (i=0; i<MAX_HASH_ENTRY; i++)
                kern_printf("%d\tvl: %d\tbl: %d\tpd: %d\t%s\n", i,
                        htable[i].valid, htable[i].blocked, htable[i].port_index,
                        htable[i].name);
*/

        kern_printf("Port des :\n");
        kern_printf("Free port des : %d\n", freeportdes);
        for (i=0; i<MAX_PORT_INT; i++)
            if (port_int[i].valid) {
                pp = &port_int[i];
                pd = &port_des[pp->port_index];
                kern_printf("%d %s  vt: %d      pn: %d\n",i,htable[pp->h_index].name,
                pd->vuoto,pd->pieno);
            }
/*
        kern_printf("Port int :\n");
        kern_printf("Free port int : %d\n", freeportint);
        for (i=0; i<MAX_PORT_INT; i++)
                kern_printf("%d  vl : %d  dm : %d  port_index : %d  proc_id : %d\n", i,
                        port_int[i].valid, port_int[i].dim_mes,
                        port_int[i].port_index, port_int[i].proc_id);
*/

}

void port_write(PORT p)
{
    struct port_ker *pd;
    struct port_com *pp;
    char msg[80];

    pp = &port_int[p];
    pd = &port_des[pp->port_index];

    kern_printf(msg,"%d  pd: %d   vt: %d      pn: %d ",p,pp->port_index,
        pd->vuoto,pd->pieno);
}

#endif