#include "semaforo.h"

/* Declare some local functions. */
FORWARD _PROTOTYPE(void init_server, (void)		);
FORWARD _PROTOTYPE(void get_work, (message *m_ptr)			);
FORWARD _PROTOTYPE(int do_up, (message *m_ptr)			);
FORWARD _PROTOTYPE(int do_down, (message *m_ptr)			);

/* semaforo globale al server */
semaforo sema;

/*===========================================================================*
 *				main                                         *
 *===========================================================================*/
PUBLIC int main(void){
        message m;
        int result;
        /* Initialize the semaphore server. */
        init_server();
        /* Main loop of server. Get work and process it. */
        while(TRUE) {
                /* Block and wait until a request message arrives. */
                get_work(&m);
                /* Caller is now blocked. Dispatch based on message type. */
                switch(m.m_type) {
                case SS_UP:      result = do_up(&m);   break;
                case SS_DOWN:    result = do_down(&m); break;
                default:          result = EINVAL;
                }
                /* Send the reply, unless the caller must be blocked. */
                if (result != EDONTREPLY) {
                        m.m_type = result;
                        send(m.m_source, &m);
                }
        }
        return(OK);
}

/*===========================================================================*
 *				 init_server                                 *
 *===========================================================================*/
PRIVATE void init_server(void){
        sema.s = 0;
        sema.quanti = 0;
}


/*===========================================================================*
 *				get_work                                     *
 *===========================================================================*/
PRIVATE void get_work(message *m_ptr){
    int status = 0;
    status = receive(ANY, m_ptr);   /* this blocks until message arrives */
    if (OK != status)
        panic("SS","failed to receive message!", status);
}

PRIVATE int do_down(message *m_ptr){
        if (sema.s > 0){
                sema.s -= 1;
                return(OK);
        }
        if (accoda(&sema, m_ptr->m_source) < 0) return(EFAULT);
        printf("Accodato %d (semaforo %d [%d])\n", 
               m_ptr->m_source, sema.s, sema.quanti);
        return(EDONTREPLY); /* non risponde: il chiamante rimane bloccato */
}

PRIVATE int do_up(message *m_ptr){
        sema.s += 1;
        if (sema.quanti > 0){
                int waiting = scoda(&sema);
                if (waiting < 0) return(EFAULT);
                sema.s -= 1;
                printf("Scodato %d (semaforo %d [%d])\n", 
                       waiting, sema.s, sema.quanti);
                m_ptr->m_type = OK;
                send(waiting, m_ptr);
        }
        return(OK);
}
