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

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