ioqueue.c 2.8 KB

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