#include "ioqueue.h" #include "../kernel/debug.h" #include "../kernel/interrupt.h" /// @brief 返回 pos 在缓冲区的下一个位置 static int32_t next_pos(int32_t pos); /// @brief 使生产者或消费者在此缓冲区上等待 /// @param waiter static void ioq_wait(struct task_struct **waiter); /// @brief 唤醒 waiter static void wakeup(struct task_struct **waiter); /// @brief 初始化 ioqueue 队列 void ioqueue_init(struct ioqueue *ioq) { lock_init(&ioq->lock); ioq->producer = NULL; ioq->consumer = NULL; ioq->head = 0; ioq->tail = 0; } /// @brief 返回 pos 在缓冲区的下一个位置 static int32_t next_pos(int32_t pos) { return (pos + 1) % BUF_SIZE; } /// @brief 判断队列是否已满 /// @param ioq /// @return TRUE OR FALSE bool ioq_full(struct ioqueue *ioq) { ASSERT(intr_get_status() == INTR_OFF); return next_pos(ioq->head) == ioq->tail; } /// @brief 判断队列是否为空 /// @param ioq /// @return TRUE OR FALSE bool ioq_empty(struct ioqueue *ioq) { ASSERT(intr_get_status() == INTR_OFF); return ioq->head == ioq->tail; } /// @brief 使生产者或消费者在此缓冲区上等待 /// @param waiter static void ioq_wait(struct task_struct **waiter) { ASSERT(*waiter == NULL && waiter != NULL); *waiter = running_thread(); thread_block(TASK_BLOCKED); // 阻塞自己 } /// @brief 唤醒 waiter static void wakeup(struct task_struct **waiter) { ASSERT(waiter != NULL); thread_unblock(*waiter); *waiter = NULL; } /// @brief 消费者从 ioq 队列中获取一个字符 char ioq_getchar(struct ioqueue *ioq) { ASSERT(intr_get_status() == INTR_OFF); // 如果 ioq 为空, 使消费者在此缓冲区上等待 // 把 ioq->consumer 记为当前线程自己, // 目的是让生产者生产后唤醒 while (ioq_empty(ioq)) { lock_acquire(&ioq->lock); ioq_wait(&ioq->consumer); lock_release(&ioq->lock); } // 获取字符并从 ioq 队列中删除 char ret = ioq->buf[ioq->tail]; ioq->tail = next_pos(ioq->tail); // 唤醒生产者 if (ioq->producer != NULL) { wakeup(&ioq->producer); } return ret; } /// @brief 生产者往 ioq 队列中添加一个字符 void ioq_putchar(struct ioqueue *ioq, char byte) { ASSERT(intr_get_status() == INTR_OFF); // 如果 ioq 已满, 使生产者在此缓冲区上等待 // 把 ioq->producer 记为当前线程自己, // 目的是让消费者消费后唤醒 while (ioq_full(ioq)) { lock_acquire(&ioq->lock); ioq_wait(&ioq->producer); lock_release(&ioq->lock); } // 往 ioq 队列中添加字符并使消费者在此缓冲区上等待 ioq->buf[ioq->head] = byte; ioq->head = next_pos(ioq->head); // 唤醒消费者 if (ioq->consumer != NULL) { wakeup(&ioq->consumer); } }