| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- #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);
- }
- }
|