ringbuffer.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2013-2014 Kevin Lange
  5. */
  6. #include <kernel/system.h>
  7. #include <kernel/ringbuffer.h>
  8. #include <kernel/process.h>
  9. size_t ring_buffer_unread(ring_buffer_t * ring_buffer) {
  10. if (ring_buffer->read_ptr == ring_buffer->write_ptr) {
  11. return 0;
  12. }
  13. if (ring_buffer->read_ptr > ring_buffer->write_ptr) {
  14. return (ring_buffer->size - ring_buffer->read_ptr) + ring_buffer->write_ptr;
  15. } else {
  16. return (ring_buffer->write_ptr - ring_buffer->read_ptr);
  17. }
  18. }
  19. size_t ring_buffer_size(fs_node_t * node) {
  20. ring_buffer_t * ring_buffer = (ring_buffer_t *)node->device;
  21. return ring_buffer_unread(ring_buffer);
  22. }
  23. size_t ring_buffer_available(ring_buffer_t * ring_buffer) {
  24. if (ring_buffer->read_ptr == ring_buffer->write_ptr) {
  25. return ring_buffer->size - 1;
  26. }
  27. if (ring_buffer->read_ptr > ring_buffer->write_ptr) {
  28. return ring_buffer->read_ptr - ring_buffer->write_ptr - 1;
  29. } else {
  30. return (ring_buffer->size - ring_buffer->write_ptr) + ring_buffer->read_ptr - 1;
  31. }
  32. }
  33. static inline void ring_buffer_increment_read(ring_buffer_t * ring_buffer) {
  34. ring_buffer->read_ptr++;
  35. if (ring_buffer->read_ptr == ring_buffer->size) {
  36. ring_buffer->read_ptr = 0;
  37. }
  38. }
  39. static inline void ring_buffer_increment_write(ring_buffer_t * ring_buffer) {
  40. ring_buffer->write_ptr++;
  41. if (ring_buffer->write_ptr == ring_buffer->size) {
  42. ring_buffer->write_ptr = 0;
  43. }
  44. }
  45. static void ring_buffer_alert_waiters(ring_buffer_t * ring_buffer) {
  46. if (ring_buffer->alert_waiters) {
  47. while (ring_buffer->alert_waiters->head) {
  48. node_t * node = list_dequeue(ring_buffer->alert_waiters);
  49. process_t * p = node->value;
  50. process_alert_node(p, ring_buffer);
  51. free(node);
  52. }
  53. }
  54. }
  55. void ring_buffer_select_wait(ring_buffer_t * ring_buffer, void * process) {
  56. if (!ring_buffer->alert_waiters) {
  57. ring_buffer->alert_waiters = list_create();
  58. }
  59. if (!list_find(ring_buffer->alert_waiters, process)) {
  60. list_insert(ring_buffer->alert_waiters, process);
  61. }
  62. list_insert(((process_t *)process)->node_waits, ring_buffer);
  63. }
  64. size_t ring_buffer_read(ring_buffer_t * ring_buffer, size_t size, uint8_t * buffer) {
  65. size_t collected = 0;
  66. while (collected == 0) {
  67. spin_lock(ring_buffer->lock);
  68. while (ring_buffer_unread(ring_buffer) > 0 && collected < size) {
  69. buffer[collected] = ring_buffer->buffer[ring_buffer->read_ptr];
  70. ring_buffer_increment_read(ring_buffer);
  71. collected++;
  72. }
  73. spin_unlock(ring_buffer->lock);
  74. wakeup_queue(ring_buffer->wait_queue_writers);
  75. if (collected == 0) {
  76. if (sleep_on(ring_buffer->wait_queue_readers) && ring_buffer->internal_stop) {
  77. ring_buffer->internal_stop = 0;
  78. break;
  79. }
  80. }
  81. }
  82. wakeup_queue(ring_buffer->wait_queue_writers);
  83. return collected;
  84. }
  85. size_t ring_buffer_write(ring_buffer_t * ring_buffer, size_t size, uint8_t * buffer) {
  86. size_t written = 0;
  87. while (written < size) {
  88. spin_lock(ring_buffer->lock);
  89. while (ring_buffer_available(ring_buffer) > 0 && written < size) {
  90. ring_buffer->buffer[ring_buffer->write_ptr] = buffer[written];
  91. ring_buffer_increment_write(ring_buffer);
  92. written++;
  93. }
  94. spin_unlock(ring_buffer->lock);
  95. wakeup_queue(ring_buffer->wait_queue_readers);
  96. ring_buffer_alert_waiters(ring_buffer);
  97. if (written < size) {
  98. if (ring_buffer->discard) {
  99. break;
  100. }
  101. if (sleep_on(ring_buffer->wait_queue_writers) && ring_buffer->internal_stop) {
  102. ring_buffer->internal_stop = 0;
  103. break;
  104. }
  105. }
  106. }
  107. wakeup_queue(ring_buffer->wait_queue_readers);
  108. ring_buffer_alert_waiters(ring_buffer);
  109. return written;
  110. }
  111. ring_buffer_t * ring_buffer_create(size_t size) {
  112. ring_buffer_t * out = malloc(sizeof(ring_buffer_t));
  113. out->buffer = malloc(size);
  114. out->write_ptr = 0;
  115. out->read_ptr = 0;
  116. out->size = size;
  117. out->alert_waiters = NULL;
  118. spin_init(out->lock);
  119. out->internal_stop = 0;
  120. out->discard = 0;
  121. out->wait_queue_readers = list_create();
  122. out->wait_queue_writers = list_create();
  123. return out;
  124. }
  125. void ring_buffer_destroy(ring_buffer_t * ring_buffer) {
  126. free(ring_buffer->buffer);
  127. wakeup_queue(ring_buffer->wait_queue_writers);
  128. wakeup_queue(ring_buffer->wait_queue_readers);
  129. ring_buffer_alert_waiters(ring_buffer);
  130. list_free(ring_buffer->wait_queue_writers);
  131. list_free(ring_buffer->wait_queue_readers);
  132. free(ring_buffer->wait_queue_writers);
  133. free(ring_buffer->wait_queue_readers);
  134. if (ring_buffer->alert_waiters) {
  135. list_free(ring_buffer->alert_waiters);
  136. free(ring_buffer->alert_waiters);
  137. }
  138. }
  139. void ring_buffer_interrupt(ring_buffer_t * ring_buffer) {
  140. ring_buffer->internal_stop = 1;
  141. wakeup_queue_interrupted(ring_buffer->wait_queue_readers);
  142. wakeup_queue_interrupted(ring_buffer->wait_queue_writers);
  143. }