2019-09-22 18:34:10 +00:00
|
|
|
#include "mailbox.h"
|
2019-09-22 18:48:11 +00:00
|
|
|
#include <semaphore.h>
|
2019-09-22 18:34:10 +00:00
|
|
|
#include <stdlib.h>
|
2019-09-22 18:48:11 +00:00
|
|
|
#include <string.h>
|
2019-09-22 18:34:10 +00:00
|
|
|
|
|
|
|
struct mailbox *mailboxes = NULL;
|
2019-09-22 18:48:11 +00:00
|
|
|
static int num_mailboxes = -1;
|
2019-09-22 18:34:10 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup the mailboxes global variable
|
|
|
|
*
|
|
|
|
* @param n The number of mailboxes to initialize.
|
|
|
|
*
|
|
|
|
* @return int 1 if the mailboxes are already allocated, -1 on error, 0 otherwise.
|
|
|
|
*/
|
|
|
|
int init_mailboxes(int n) {
|
|
|
|
if (mailboxes != NULL) {
|
|
|
|
return 1;
|
2019-09-22 18:48:11 +00:00
|
|
|
} else if (n <= 0) {
|
|
|
|
return -1;
|
2019-09-22 18:34:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mailboxes = calloc(n, sizeof(struct mailbox));
|
2019-09-22 18:48:11 +00:00
|
|
|
num_mailboxes = n;
|
2019-09-22 18:34:10 +00:00
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
int sem_result = sem_init(&mailboxes[i].send_sem, 0, 1);
|
|
|
|
if (sem_result != 0) {
|
|
|
|
free(mailboxes);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sem_result = sem_init(&mailboxes[i].recv_sem, 0, 0);
|
|
|
|
if (sem_result != 0) {
|
|
|
|
free(mailboxes);
|
|
|
|
sem_destroy(&mailboxes[i].send_sem);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free the mailboxes global variable.
|
|
|
|
*/
|
|
|
|
void free_mailboxes() {
|
|
|
|
if (mailboxes == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2019-09-22 22:33:00 +00:00
|
|
|
for (int i = 0; i < num_mailboxes; i++) {
|
|
|
|
sem_destroy(&mailboxes[i].send_sem);
|
|
|
|
sem_destroy(&mailboxes[i].recv_sem);
|
|
|
|
}
|
2019-09-22 18:34:10 +00:00
|
|
|
|
|
|
|
free(mailboxes);
|
|
|
|
// Mark mailboxes as null so freeing is idempotent.
|
|
|
|
mailboxes = NULL;
|
2019-09-22 18:48:11 +00:00
|
|
|
num_mailboxes = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send a message to the given mailbox. Blocks if the mailbox is full.
|
|
|
|
*
|
|
|
|
* @param dest The index of the mailbox to send to.
|
|
|
|
* @param message The message to send to the mailbox. Will be copied into the mailbox.
|
|
|
|
*
|
|
|
|
* @reutrn int -1 on error, 0 otherwise.
|
|
|
|
*/
|
|
|
|
int SendMsg(int dest, struct msg *message) {
|
|
|
|
if (dest >= num_mailboxes || dest < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct mailbox *dest_mailbox = &mailboxes[dest];
|
|
|
|
int wait_result = sem_wait(&dest_mailbox->send_sem);
|
|
|
|
if (wait_result != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&dest_mailbox->stored_message, message, sizeof(struct msg));
|
|
|
|
// Signal that someone can recieve a message, now that it's stored.
|
|
|
|
sem_post(&dest_mailbox->recv_sem);
|
|
|
|
|
2019-09-22 19:05:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-24 07:07:21 +00:00
|
|
|
/**
|
|
|
|
* Send a message to the given mailbox. Returns immediately if the mailbox is full.
|
|
|
|
*
|
|
|
|
* @param dest The index of the mailbox to send to.
|
|
|
|
* @param message The message to send to the mailbox. Will be copied into the mailbox.
|
|
|
|
*
|
|
|
|
* @reutrn int -1 on error, 0 otherwise. If the mailbox is full, errno will equal EAGAIN
|
|
|
|
*/
|
|
|
|
int NBSendMsg(int dest, struct msg *message) {
|
|
|
|
if (dest >= num_mailboxes || dest < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct mailbox *dest_mailbox = &mailboxes[dest];
|
|
|
|
int wait_result = sem_trywait(&dest_mailbox->send_sem);
|
|
|
|
if (wait_result != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&dest_mailbox->stored_message, message, sizeof(struct msg));
|
|
|
|
// Signal that someone can recieve a message, now that it's stored.
|
|
|
|
sem_post(&dest_mailbox->recv_sem);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-22 19:05:12 +00:00
|
|
|
/**
|
|
|
|
* Receive a message from the given mailbox.
|
|
|
|
*
|
|
|
|
* @param mailbox_index The index of the mailbox to receive from.
|
|
|
|
* @param message A pointer to an already allocated message struct to store the recieved message in.
|
|
|
|
* @return int -1 on error, 0 otherwise.
|
|
|
|
*/
|
|
|
|
int RecvMsg(int mailbox_index, struct msg *message) {
|
|
|
|
if (mailbox_index >= num_mailboxes || mailbox_index < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct mailbox *src_mailbox = &mailboxes[mailbox_index];
|
|
|
|
int wait_result = sem_wait(&src_mailbox->recv_sem);
|
|
|
|
if (wait_result != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(message, &src_mailbox->stored_message, sizeof(struct msg));
|
|
|
|
// Signal that someone can send a message to this mailbox now that we've taken the message out.
|
|
|
|
sem_post(&src_mailbox->send_sem);
|
|
|
|
|
2019-09-22 18:48:11 +00:00
|
|
|
return 0;
|
2019-09-22 18:34:10 +00:00
|
|
|
}
|