--- /dev/null
+#include <spinlock.h>
+#include <sem.h>
+#include "mailbox.h"
+
+int mailbox_init(struct mailbox *mbox)
+{
+ int ret_val;
+
+ ret_val = -EINVAL;
+
+ if(mbox) {
+ /* zero the entire mailbox */
+ memset(mbox, 0, sizeof(*mbox));
+
+ /* this should really always return zero */
+ ret_val = sem_post(&(mbox->mb_wsem));
+ }
+
+ return(ret_val);
+}
+
+int mailbox_put(struct mailbox *mbox, void *msg)
+{
+ int ret_val;
+
+ ret_val = -EINVAL;
+
+ if(mbox) {
+ /*
+ * Wait until the mailbox is available. The sem_wait()
+ * function always succeeds, so we don't need to bother
+ * checking its return value
+ */
+ sem_wait(&(mbox->mb_wsem));
+
+ /* place the message in the mailbox */
+ mbox->mb_msg = msg;
+
+ /*
+ * Notify receivers that a message is ready to be received.
+ * Since we're only putting one message at a time into the
+ * mailbox, this really shouldn't overflow. If it does, some
+ * other part of the kernel must have overwritten the memory
+ * of we have a use-after-free bug. Either way, the mailbox
+ * isn't really safe to use anymore.
+ */
+ ret_val = sem_post(&(mbox->mb_rsem));
+
+ if(!ret_val) {
+ /* wait for synchronization */
+ ret_val = sem_wait(&(mbox->mb_ssem));
+ } else {
+ /* put the semaphore back into its original state */
+ sem_post(&(mbox->mb_wsem));
+ }
+ }
+
+ return(ret_val);
+}
+
+int mailbox_get(struct mailbox *mbox, void **dst)
+{
+ int ret_val;
+
+ ret_val = -EINVAL;
+
+ if(mbox) {
+ /*
+ * Wait for a message to be placed in the mailbox. This
+ * function always succeeds, so we don't have to check its
+ * return value.
+ */
+ sem_wait(&(mbox->mb_rsem));
+
+ /* retrieve the message */
+ *dst = mbox->mb_msg;
+
+ /*
+
+ }
+
+ return(ret_val);
+}
--- /dev/null
+#ifndef _MAILBOX_H
+#define _MAILBOX_H
+
+#include <spinlock.h>
+#include <sem.h>
+
+/*
+ * DESIGN OF THE IPC-MAILBOXES
+ *
+ * Similar to the IPC mechanism in Minix, we try to avoid deadlocks
+ * by forcing processes to rendevouz during message transmission. That
+ * means, the sending process waits for the recipient to accept and
+ * acknowledge the message before continuing execution. This is
+ * achieved through the use of two semaphores and a mutex as shown in
+ * the following figure. The '+' and '=' characters signify
+ * non-blocking and blocking calls, respectively. The --< | <-- thing
+ * is supposed to be a bridge (it seemed to be the best way to draw a
+ * non-planar graph in ASCII).
+ *
+ * SEND_TASK RECV_TASK
+ * | |
+ * +--(mutex_lock)--= |
+ * | | +------+ |
+ * | +----(MOV)--->| slot |<---(MOV)--< | <--.
+ * | | +------+ | |
+ * | | | |
+ * | | +------+ | |
+ * v +-(sem_post)->| wsem |<-(sem_wait)-= |
+ * +-------+ | +------+ | |
+ * | mutex | | +----'
+ * +-------+ | +------+ |
+ * ^ =-(sem_wait)->| ssem |<-(sem_post)-+
+ * | | +------+ |
+ * '-(mutex_unlock)-+ |
+ * | |
+ * X X
+ *
+ * The following petri net describes that configuration:
+ *
+ * .---.
+ * .--->|s01|----.
+ * | '---' |
+ * | v
+ * ----- -----
+ * ^ ^ | | .---. |
+ * | | | '-->|x00|---->|---.
+ * | '----. | '---' | |
+ * | | | .-->| |
+ * | | | | | |
+ * | | v | v
+ * .---. .---. .---. .---. .---.
+ * |s00| |x02| |s02| |r00| |r01|
+ * '---' '---' '---' '---' '---'
+ * ^ ^ | ^ |
+ * | | | | | |
+ * | .----' | '---| |
+ * | | | .---. |<--'
+ * | | | .---|x01|<----|
+ * ----- | | '---' |
+ * ^ v v
+ * | -----
+ * | .---. |
+ * '---|s03|<----'
+ * '---'
+ *
+ * The sending task will start in position s00 and the receiving task
+ * will start in r00. Positions x00 and x01 are the semaphores, and
+ * position x02 is the mutex.
+ *
+ * The state vector has the following columns:
+ * 0 1 2 3 4 5 6 7 8
+ * m = (s00, s01, s02, s03, r00, r01, x00, x01, x02)
+ *
+ * From the diagram, we get the following state vector for time n:
+ *
+ * m(n) = (
+ * m(n-1, 3),
+ * ( m(n-1, 0) + m(n-1, 6) ) / 2,
+ * m(n-1, 1),
+ * ( m(n-1, 2) + m(n-1, 8) ) / 2,
+ * m(n-1, 5),
+ * ( m(n-1, 7) + m(n-1, 4) ) / 2
+ * m(n-1, 3),
+ * m(n-1, 1),
+ * m(n-1, 5)
+ * )
+ *
+ * TODO: Proof that petri net is deadlock-free.
+ */
+
+struct mailbox {
+ mutex_t mb_lock;
+ sem_t mb_rsem;
+ sem_t mb_ssem;
+ void *mb_msg;
+};
+
+/*
+ * mailbox_init() - Initialize a mailbox
+ *
+ * SYNOPSIS
+ * int mailbox_init(struct mailbox *mbox);
+ *
+ * DESCRIPTION
+ * The mailbox_init() function initializes the mailbox pointed to by
+ * `mbox'. The function will zero all space occupied by the mailbox
+ * and initialize the semaphores used for synchronization.
+ *
+ * RETURN VALUE
+ * 0 The mailbox was successfully initialized
+ * -EINVAL Invalid mailbox specified
+ */
+int mailbox_init(struct mailbox*);
+
+/*
+ * mailbox_put() - Put a message into a mailbox
+ *
+ * SYNOPSIS
+ * int mailbox_put(struct mailbox *mbox, void *msg);
+ *
+ * DESCRIPTION
+ * The mailbox_put() function puts the message pointed to by `msg'
+ * into the mailbox pointed to by `mbox' and waits for another task
+ * to receive the message. If the mailbox cannot immediately be
+ * written to (for example, because another task has put a message
+ * inside), the caller will be suspended until the mailbox becomes
+ * available. Once the function returns, the caller can be certain
+ * that the message has been accepted by the receiving task.
+ *
+ * RETURN VALUE
+ * 0 The message successfully transmitted to another task
+ * -EINVAL Invalid mailbox specified
+ * -EOVERFLOW A kernel bug has occured
+ */
+int mailbox_put(struct mailbox*, void*);
+
+/*
+ * mailbox_get() - Get a message from a mailbox
+ *
+ * SYNOPSIS
+ * int mailbox_get(struct mailbox *mbox, void **dst);
+ *
+ * DESCRIPTION
+ * The mailbox_get() function retrieves a message from the mailbox
+ * pointed to by `mbox' and adjusts the pointer pointed to by `dst'
+ * to point to the retrieved message. If there is no message waiting
+ * to be retrieved, the calling task will be suspended until a
+ * message can be retrieved. The sending and receiving tasks will
+ * rendevouz during the message transmission, meaning that the sender
+ * will wait for the message to be retrieved by a receiving task.
+ *
+ * RETURN VALUE
+ * 0 A message was successfully retrieved from the mailbox
+ * -EINVAL Invalid mailbox specified
+ * -EOVERFLOW An overflow occured during the rendevouz. This error
+ * means that the mailbox was overwritten with invalid
+ * data due to a kernel bug
+ */
+int mailbox_get(struct mailbox*, void**);
+
+#endif /* _MAILBOX_H */