All pastes #945892 Raw Edit

Mine

public text v1 · immutable
·published 2008-03-17 07:55 UTC
rendered paste body
/*
* srr.c
*Naomi Aro
*0424556
*March 14 2008
*/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include "srr.h"

enum state {IDLE, ACTIVE};
enum mail {UNREAD, READ};
enum reply {REPLIED, NOTREPLIED};
typedef struct mailbox mbox;
typedef struct message mail;

struct mailbox{
        pthread_t tid;          //thread ID of owner
        pthread_cond_t changed;
        enum state send_state;
        enum state receive_state;
        mbox *next;
};

struct message{
        pthread_t from;
        pthread_t to;
        char *sbuff;
        int sblen;
        char *rbuff;
        int rblen;
        enum mail mail_state;
        enum reply reply_state;
        mail *next;
};

static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static mbox *mailboxes = NULL;
static mail *messages = NULL;

/*
*
*get_mailbox
*finds the mailbox belonging to pthread thread.
*If the thread does not yet have a mailbox one is created and added to the front
 of the mailbox list.
*
*/

mbox *get_mbox( pthread_t thread ){
        mbox *m;

        for( m=mailboxes; m!=NULL; m=m->next ){
                if( pthread_equal( thread, m->tid )){
                        return m;
                }
        }

        m = (mbox *)malloc( sizeof(mbox) );
        m->tid = thread;
        m->send_state = IDLE;
        m->receive_state = IDLE;
        pthread_cond_init( &(m->changed), NULL);

        if( mailboxes == NULL ){
                m->next = NULL;
                mailboxes = m;
        }
        else{
                m->next = mailboxes;
                mailboxes = m;
        }


        return m;
}



/*
 * msg_send
 *
 * Send the message msg to the receiver.  The sender is blocked until the
 * receiver replies with its own message, which is placed in the reply buffer.
 *
 */
void msg_send(  pthread_t receiver, char *msg, int msglen, char *reply, int *rep
len ){
        mbox *from, *to;
        mail *letter;
        mail *m, *prev, *next, *garbage;
        int rlen = *replen;

        pthread_mutex_lock( &lock );

        from = get_mbox( pthread_self() );
        to = get_mbox( receiver );


        /*
        *If the list of messages is empty you can stick the first letter
        *at the beginning of the linked list of mails.
        *Otherwise the most recently received mail will be stuck at the end
        *of the linked list of mails.
        */

        letter = (mail *)malloc(sizeof(mail));
        letter->sbuff = (char *)malloc( msglen );
        letter->sbuff = memcpy(letter->sbuff, msg, msglen);
        letter->sblen = msglen;
        from->send_state = ACTIVE;
        letter->mail_state = UNREAD;
        letter->reply_state = NOTREPLIED;
        to->receive_state = ACTIVE;
        letter->from = pthread_self();
        letter->to = receiver;


        if( messages == NULL ){
                messages = letter;

        }
        else{
                m=messages;

                while(1){
                        if(m->next == NULL){
                                m->next= letter;
                                break;
                        }
                        m = m->next;
                }
        }


        //a message has been sent, if a receive is waiting it must be signalled.
        pthread_cond_signal( &(to->changed));

        //a thread has sent its message and it must block itself until it receiv
es a reply.
        while( from->send_state == ACTIVE )
                pthread_cond_wait( &(from->changed), &lock );

        reply = memcpy(reply, letter->rbuff, rlen);


        //free the space of the letter as it has served its purpose.
        m = messages;
        prev = messages;

        while(1){
                if(m->reply_state == REPLIED){
                        garbage = m;
                        next = m->next;
                        prev->next = next;
                        free(garbage);
                        break;
                }
        prev = m;
        m = m->next;
        }

        pthread_mutex_unlock( &lock );
        return;

}


/*
 * msg_receive
 *
 * Receive a message from any sender thread.  Receiver's thread is blocked
 * until a message is available.  The sender's thread ID is returned so
 * that msg_reply can later be called (sender is blocked awaiting reply).
 * The reply will not be received until msg_reply is called.
 */


pthread_t msg_receive( char *sbuffer, int *maxlen ){
        mbox *to;
        mail *letter;
        mail *m;
        pthread_t sid;
        int len = *maxlen;

        pthread_mutex_lock( &lock );
        to = get_mbox( pthread_self());

        //waits for a message to arrive so it can receive.
        while( to->receive_state == IDLE )
                pthread_cond_wait( &(to->changed), &lock );

        //once there is at least one message, checks if it has already been rece
ived.
        m=messages;
        while(m->next != NULL ){
                if(m->mail_state == UNREAD){
                        //the message is ment for this thread.
                        if(pthread_equal(m->to, pthread_self())){
                                break;
                        }
                }
                else{
                        m=m->next;
                }
        }

        letter = m;
        sid = letter->from;
        letter->mail_state = READ;
        sbuffer = memcpy(sbuffer, letter->sbuff, len );

        //checks to see if there are anymore messages for this thread, if not se
t receive_state to IDLE.
        m = letter;
        while(1){
                if(m->next == NULL){
                        to->receive_state = IDLE;
                        break;
                }
                m=m->next;
                if(pthread_equal(m->to, pthread_self())){
                        break;
                }
        }

        pthread_mutex_unlock( &lock );

return sid;
}



/*
 * msg_reply
 *
 * Copy the reply into the sender's reply buffer and restart the
 * sender.
 * If no message was received from the designated
 * sender thread, via prior msg_receive, the results are undefined.
 */


void msg_reply( pthread_t sender, char *msg, int len ){
        mbox *to, *from;
        mail *letter;


        printf( "thread %x in msg_reply replying to %x\n",(unsigned int)pthread_
self(), (unsigned int)sender);

        pthread_mutex_lock( &lock );

        from = get_mbox( sender );
        to = get_mbox( pthread_self() );
        letter = messages;

        while(1){
                printf("message sender: %x\n",(unsigned int)letter->from);
                if(letter->next == NULL){
                        break;
                }
                letter = letter->next;
        }

        letter = messages;

        //reply to msg sent by sender.
        while(1){
                printf("checking for message from sender\n");
                if(letter->reply_state == REPLIED){
                        if(letter->next != NULL){
                                letter= letter->next;
                        }
                }
                else{
                        if(pthread_equal(sender, letter->from)){
                                break;
                        }
                letter = letter->next;
                }

        }
        printf( "thread %x in msg_reply replying to %x FOUND LETTER\n",(unsigned int)pthread_self(), (unsigned int)sender);

        letter->rbuff = (char*)malloc(len);
        letter->rbuff = memcpy(letter->rbuff, msg, len);
        letter->rblen = len;
        letter->reply_state = REPLIED;
        from->send_state = IDLE;

        //wake up sender thread after the message has been replied to.
        pthread_cond_signal( &(from->changed) );

        pthread_mutex_unlock( &lock );
return;
}