+#include "queue.h"
+#include <stdlib.h>
+#include <pthread.h>
+
+/* Requirements 4 & 5 for Homework 09 indicate that you should modify the add
+ * and pop methods for the queue to provide for thread safety. If you modify
+ * the producer and consumer methods instead you will not receive full credit
+ * for the solution. Additionally, the due date for the homework is now
+ * Thursday to provide for the necessary modifications to fulfill requirements
+ * 4 & 5. Please note that you should NOT be using a global mutex. Any
+ * structures you use to protect the queue should be associated with the
+ * particular queue that is being used (the one given to the add/pop methods).
+ * */
+
+/* private methods */
+
+static void clear_node(queue_node_t* node)
+{
+ if (node != NULL)
+ {
+ clear_node(node->next);
+ free(node);
+ }
+}
+
+static queue_node_t* create_node(int value)
+{
+ queue_node_t* node = malloc(sizeof(queue_node_t));
+ node->value = value;
+ node->next = NULL;
+ return node;
+}
+
+/* public methods */
+
+void queue_init(queue_t* queue)
+{
+ queue->root = NULL;
+
+ queue->mx_pop = (pthread_mutex_t *) calloc(1, sizeof(pthread_mutex_t));
+ queue->mx_push = (pthread_mutex_t *) calloc(1, sizeof(pthread_mutex_t));
+ queue->mx_valid_root = (pthread_mutex_t *) calloc(1, sizeof(pthread_mutex_t));
+ queue->valid_root = (pthread_cond_t *) calloc(1, sizeof(pthread_cond_t));
+
+ pthread_mutex_init(queue->mx_pop, NULL);
+ pthread_mutex_init(queue->mx_push, NULL);
+ pthread_mutex_init(queue->mx_valid_root, NULL);
+
+ pthread_cond_init(queue->valid_root, NULL);
+
+ return;
+}
+
+void queue_clear(queue_t* queue)
+{
+ clear_node(queue->root);
+ free(queue->mx_pop);
+ free(queue->mx_push);
+ free(queue->valid_root);
+ return;
+}
+
+/* edit */
+void queue_add(queue_t* queue, int value)
+{
+ pthread_mutex_lock(queue->mx_push);
+ pthread_mutex_lock(queue->mx_valid_root);
+
+ if (queue->root == NULL)
+ {
+ queue->root = create_node(value);
+ pthread_cond_signal(queue->valid_root);
+ pthread_mutex_unlock(queue->mx_valid_root);
+ }
+ else
+ {
+ pthread_cond_signal(queue->valid_root);
+ pthread_mutex_unlock(queue->mx_valid_root);
+
+ queue_node_t* last = queue->root;
+ while (last->next != NULL)
+ {
+ last = last->next;
+ }
+ last->next = create_node(value);
+ }
+ pthread_mutex_unlock(queue->mx_push);
+ return;
+}
+
+/* edit */
+int queue_pop(queue_t* queue)
+{
+ if(queue->root == NULL) {
+
+ pthread_mutex_lock(queue->mx_valid_root);
+ pthread_cond_wait(queue->valid_root, queue->mx_valid_root);
+ pthread_mutex_unlock(queue->mx_valid_root);
+ }
+ pthread_mutex_lock(queue->mx_pop);
+ queue_node_t* temp = queue->root->next;
+ int value = queue->root->value;
+ free(queue->root);
+ queue->root = temp;
+ pthread_mutex_unlock(queue->mx_pop);
+ return value;
+}