cs-3013-assignment-3/mailbox.c

136 lines
3.3 KiB
C
Raw Normal View History

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
}