Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

thread-link.cpp 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #include "../thread-link.h"
  2. namespace rtosc {
  3. #ifdef off_t
  4. #undef off_t
  5. #endif
  6. #define off_t signed long
  7. //Ringbuffer internal structure
  8. //XXX possible undefined behavior depending on future semantics of volatile
  9. struct internal_ringbuffer_t {
  10. char *buffer;
  11. volatile off_t write;
  12. volatile off_t read;
  13. size_t size;
  14. };
  15. typedef internal_ringbuffer_t ringbuffer_t;
  16. static size_t ring_read_size(ringbuffer_t *ring)
  17. {
  18. const size_t w = ring->write;
  19. const size_t r = ring->read;
  20. return (w-r+ring->size) % ring->size;
  21. }
  22. static size_t ring_write_size(ringbuffer_t *ring)
  23. {
  24. //leave one forbidden element
  25. const size_t w = ring->write;
  26. const size_t r = ring->read;
  27. if(r == w)
  28. return ring->size - 1;
  29. return ((r - w + ring->size) % ring->size) - 1;
  30. }
  31. static void ring_write(ringbuffer_t *ring, const char *data, size_t len)
  32. {
  33. assert(ring_write_size(ring) >= len);
  34. const off_t next_write = (ring->write + len)%ring->size;
  35. //discontinuous write
  36. if(next_write < ring->write) {
  37. const size_t w1 = ring->size - ring->write - 1;
  38. const size_t w2 = len - w1;
  39. memcpy(ring->buffer+ring->write, data, w1);
  40. memcpy(ring->buffer, data+w1, w2);
  41. } else { //contiguous
  42. memcpy(ring->buffer+ring->write, data, len);
  43. }
  44. ring->write = next_write;
  45. }
  46. static void ring_read(ringbuffer_t *ring, char *data, size_t len)
  47. {
  48. assert(ring_read_size(ring) >= len);
  49. const off_t next_read = (ring->read + len)%ring->size;
  50. //discontinuous read
  51. if(next_read < ring->read) {
  52. const size_t r1 = ring->size - ring->read - 1;
  53. const size_t r2 = len - r1;
  54. memcpy(data, ring->buffer+ring->read, r1);
  55. memcpy(data+r1, ring->buffer, r2);
  56. } else { //contiguous
  57. memcpy(data, ring->buffer+ring->read, len);
  58. }
  59. ring->read = next_read;
  60. }
  61. static void ring_read_vector(ringbuffer_t *ring, ring_t *r)
  62. {
  63. assert(r);
  64. size_t read_size = ring_read_size(ring);
  65. off_t read = ring->read;
  66. r[0].data = ring->buffer+ring->read;
  67. if(read_size+read > ring->size) { //discontinuous
  68. size_t r2 = (read_size+1+read)%ring->size;
  69. size_t r1 = read_size - r2;
  70. r[0].len = r1;
  71. r[1].data = ring->buffer;
  72. r[1].len = r2;
  73. } else {
  74. r[0].len = read_size;
  75. r[1].data = NULL;
  76. r[1].len = 0;
  77. }
  78. }
  79. ThreadLink::ThreadLink(size_t max_message_length, size_t max_messages)
  80. :MaxMsg(max_message_length),
  81. BufferSize(MaxMsg*max_messages),
  82. write_buffer(new char[MaxMsg]),
  83. read_buffer(new char[MaxMsg]),
  84. ring(new ringbuffer_t)
  85. {
  86. ring->buffer = new char[BufferSize];
  87. ring->size = BufferSize;
  88. ring->read = 0;
  89. ring->write = 0;
  90. memset(write_buffer, 0, MaxMsg);
  91. memset(read_buffer, 0, MaxMsg);
  92. }
  93. ThreadLink::~ThreadLink(void)
  94. {
  95. delete[] ring->buffer;
  96. delete ring;
  97. delete[] write_buffer;
  98. delete[] read_buffer;
  99. }
  100. void ThreadLink::write(const char *dest, const char *args, ...)
  101. {
  102. va_list va;
  103. va_start(va,args);
  104. const size_t len =
  105. rtosc_vmessage(write_buffer,MaxMsg,dest,args,va);
  106. va_end(va);
  107. if(ring_write_size(ring) >= len)
  108. ring_write(ring,write_buffer,len);
  109. }
  110. void ThreadLink::writeArray(const char *dest, const char *args, const rtosc_arg_t *aargs)
  111. {
  112. const size_t len =
  113. rtosc_amessage(write_buffer, MaxMsg, dest, args, aargs);
  114. if(ring_write_size(ring) >= len)
  115. ring_write(ring,write_buffer,len);
  116. }
  117. /**
  118. * Directly write message to ringbuffer
  119. */
  120. void ThreadLink::raw_write(const char *msg)
  121. {
  122. const size_t len = rtosc_message_length(msg, -1);//assumed valid
  123. if(ring_write_size(ring) >= len)
  124. ring_write(ring,msg,len);
  125. }
  126. /**
  127. * @returns true iff there is another message to be read in the buffer
  128. */
  129. bool ThreadLink::hasNext(void) const
  130. {
  131. return ring_read_size(ring);
  132. }
  133. /**
  134. * Read a new message from the ringbuffer
  135. */
  136. msg_t ThreadLink::read(void) {
  137. ring_t r[2];
  138. ring_read_vector(ring,r);
  139. const size_t len =
  140. rtosc_message_ring_length(r);
  141. assert(ring_read_size(ring) >= len);
  142. assert(len <= MaxMsg);
  143. ring_read(ring, read_buffer, len);
  144. return read_buffer;
  145. }
  146. /**
  147. * Peak at last message read without reading another
  148. */
  149. msg_t ThreadLink::peak(void) const
  150. {
  151. return read_buffer;
  152. }
  153. /**
  154. * Raw write buffer access for more complicated task
  155. */
  156. char *ThreadLink::buffer(void) {return write_buffer;}
  157. /**
  158. * Access to write buffer length
  159. */
  160. size_t ThreadLink::buffer_size(void) const {return BufferSize;}
  161. };