ioqueue.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #include "ioqueue.h"
  2. #include "../kernel/debug.h"
  3. #include "../kernel/interrupt.h"
  4. /// @brief 返回 pos 在缓冲区的下一个位置
  5. static int32_t next_pos(int32_t pos);
  6. /// @brief 初始化 ioqueue 队列
  7. void ioqueue_init(struct ioqueue *ioq)
  8. {
  9. lock_init(&ioq->lock);
  10. ioq->producer = NULL;
  11. ioq->consumer = NULL;
  12. ioq->head = 0;
  13. ioq->tail = 0;
  14. }
  15. /// @brief 返回 pos 在缓冲区的下一个位置
  16. static int32_t next_pos(int32_t pos)
  17. {
  18. return (pos + 1) % BUF_SIZE;
  19. }
  20. /// @brief 判断队列是否已满
  21. /// @param ioq
  22. /// @return TRUE OR FALSE
  23. bool ioq_full(struct ioqueue *ioq)
  24. {
  25. ASSERT(intr_get_status() == INTR_OFF);
  26. return next_pos(ioq->head) == ioq->tail;
  27. }
  28. /// @brief 判断队列是否为空
  29. /// @param ioq
  30. /// @return TRUE OR FALSE
  31. bool ioq_empty(struct ioqueue *ioq)
  32. {
  33. ASSERT(intr_get_status() == INTR_OFF);
  34. return ioq->head == ioq->tail;
  35. }
  36. /// @brief 使生产者或消费者在此缓冲区上等待
  37. /// @param waiter
  38. static void ioq_wait(struct task_struct **waiter)
  39. {
  40. ASSERT(*waiter == NULL && waiter != NULL);
  41. *waiter = running_thread();
  42. thread_block(TASK_BLOCKED); // 阻塞自己
  43. }
  44. /// @brief 唤醒 waiter
  45. static void wakeup(struct task_struct **waiter)
  46. {
  47. ASSERT(waiter != NULL);
  48. thread_unblock(*waiter);
  49. *waiter = NULL;
  50. }
  51. /// @brief 消费者从 ioq 队列中获取一个字符
  52. char ioq_getchar(struct ioqueue *ioq)
  53. {
  54. ASSERT(intr_get_status() == INTR_OFF);
  55. // 如果 ioq 为空, 使消费者在此缓冲区上等待
  56. // 把 ioq->consumer 记为当前线程自己,
  57. // 目的是让生产者生产后唤醒
  58. while (ioq_empty(ioq))
  59. {
  60. lock_acquire(&ioq->lock);
  61. ioq_wait(&ioq->consumer);
  62. lock_release(&ioq->lock);
  63. }
  64. // 获取字符并从 ioq 队列中删除
  65. char ret = ioq->buf[ioq->tail];
  66. ioq->tail = next_pos(ioq->tail);
  67. // 唤醒生产者
  68. if (ioq->producer != NULL)
  69. {
  70. wakeup(&ioq->producer);
  71. }
  72. return ret;
  73. }
  74. /// @brief 生产者往 ioq 队列中添加一个字符
  75. void ioq_putchar(struct ioqueue *ioq, char byte)
  76. {
  77. ASSERT(intr_get_status() == INTR_OFF);
  78. // 如果 ioq 已满, 使生产者在此缓冲区上等待
  79. // 把 ioq->producer 记为当前线程自己,
  80. // 目的是让消费者消费后唤醒
  81. while (ioq_full(ioq))
  82. {
  83. lock_acquire(&ioq->lock);
  84. ioq_wait(&ioq->producer);
  85. lock_release(&ioq->lock);
  86. }
  87. // 往 ioq 队列中添加字符并使消费者在此缓冲区上等待
  88. ioq->buf[ioq->head] = byte;
  89. ioq->head = next_pos(ioq->head);
  90. // 唤醒消费者
  91. if (ioq->consumer != NULL)
  92. {
  93. wakeup(&ioq->consumer);
  94. }
  95. }