#include "mailbox.h" #include #include #include struct mailbox *mailboxes = NULL; static int num_mailboxes = -1; /** * 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; } else if (n <= 0) { return -1; } mailboxes = calloc(n, sizeof(struct mailbox)); num_mailboxes = n; 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; } for (int i = 0; i < num_mailboxes; i++) { sem_destroy(&mailboxes[i].send_sem); sem_destroy(&mailboxes[i].recv_sem); } free(mailboxes); // Mark mailboxes as null so freeing is idempotent. mailboxes = NULL; 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); return 0; } /** * 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; } /** * 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); return 0; }