All pastes #764260 Raw Edit

Unnamed

public text v1 · immutable
·published 2007-11-07 01:51 UTC
rendered paste body
/*
 * Implementation of the mailbox.
 * Implementation notes: 
 *
 * The mailbox is protected with a lock to make sure that only 
 * one process is within the queue at any time. 
 *
 * It also uses condition variables to signal that more space or
 * more messages are available. 
 * In other words, this code can be seen as an example of implementing a
 * producer-consumer problem with a monitor and condition variables. 
 *
 * Note that this implementation only allows keys from 0 to 4 
 * (key >= 0 and key < MAX_Q). 
 *
 * The buffer is a circular array. 
*/

#include "common.h"
#include "thread.h"
#include "mbox.h"
#include "util.h"

mbox_t Q[MAX_MBOX];


/*
 * Returns the number of bytes available in the queue
 * Note: Mailboxes with count=0 messages should have head=tail, which
 * means that we return BUFFER_SIZE bytes.
 */
static int space_available(mbox_t * q)
{
	if ((q->tail == q->head) && (q->count != 0)) {
		/* Message in the queue, but no space  */
		return 0;
	}

	if (q->tail > q->head) {
		/* Head has wrapped around  */
		return q->tail - q->head;
	}
	/* Head has a higher index than tail  */
	return q->tail + BUFFER_SIZE - q->head;
}

/* Initialize mailbox system, called by kernel on startup  */
void mbox_init(void)
{
	mbox_t *box;
	int i;
	for(i = 0; i < MAX_MBOX; i++){
		box = &Q[i];
		box->used = 0;
		lock_init(&box->l);
		condition_init(&box->moreSpace);
		condition_init(&box->moreData);
		box->count = 0;
		box->head = 0;
		box->tail = 0;
	}
}

/*
 * Open a mailbox with the key 'key'. Returns a mailbox handle which
 * must be used to identify this mailbox in the following functions
 * (parameter q).
 */
int mbox_open(int key)
{
	mbox_t *box;
	if (key < 0 || key >= MAX_MBOX)
		return -1;

	box = &Q[key];
	lock_acquire(&box->l);

	if (!box->used) {
		box->count = 0;
		box->head = 0;
		box->tail = 0;
	}
	box->used++;

	lock_release(&box->l);
	return key;
}

/* Close the mailbox with handle q  */
int mbox_close(int q)
{
	mbox_t *box;
	if (q < 0 || q >= MAX_MBOX)
		return -1;

	box = &Q[q];
	lock_acquire(&box->l);
	/* We could assert here that box->used > 0 */
	box->used--;
	lock_release(&box->l);
	return 1;
}

/*
 * Get number of messages (count) and number of bytes available in the
 * mailbox buffer (space). Note that the buffer is also used for
 * storing the message headers, which means that a message will take
 * MSG_T_HEADER + m->size bytes in the buffer. (MSG_T_HEADER =
 * sizeof(msg_t header))
 */
int mbox_stat(int q, int *count, int *space)
{
	mbox_t *box = &Q[q];
	lock_acquire(&box->l);
	*count = box->count;
	*space = space_available(box);
	lock_release(&box->l);
	return 1;		/*whatever - not a single caller checks the return value*/
}

/* Fetch a message from queue 'q' and store it in 'm'  */
int mbox_recv(int q, msg_t * m)
{
	mbox_t *box = &Q[q];
	int sz;
	int i;

	lock_acquire(&box->l);
	while (box->count < 1)
		condition_wait(&box->l, &box->moreData);

	/* the size field can also be fragmented, so assemble it into m */
	for (i = 0; i < MSG_T_HEADER_SIZE; i++)
		((char *)m)[i] = box->buffer[(box->tail + i) % BUFFER_SIZE];

	sz = MSG_SIZE(m);

	for(; i < sz; i++)
		((char *)m)[i] = box->buffer[(box->tail + i) % BUFFER_SIZE];

	box->tail = (box->tail + sz) % BUFFER_SIZE;
	box->count--;
	/* notfiy everyone so that a message will be sent if *any* process has a
	   message that fits into the buffer */
	condition_broadcast(&box->moreSpace);
	lock_release(&box->l);
	return sz;		/*whatever - not a single caller checks the return value*/
}

/* Insert 'm' into the mailbox 'q'  */
int mbox_send(int q, msg_t * m)
{
	mbox_t *box = &Q[q];
	int sz = MSG_SIZE(m);
	int i;
	lock_acquire(&box->l);
	while (space_available(box) < sz)
		condition_wait(&box->l, &box->moreSpace);

	for (i = 0; i < sz; i++)
		box->buffer[(box->head + i) % BUFFER_SIZE] = ((char *)m)[i];

	box->head = (box->head + sz) % BUFFER_SIZE;
	box->count++;
	condition_signal(&box->moreData);
	lock_release(&box->l);
	return sz;		/*whatever - not a single caller checks the return value*/
}