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.

MultiPseudoStack.cpp 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. MultiPseudoStack.cpp - Multiple-Writer Lock Free Datastructure
  4. Copyright (C) 2016 Mark McCurry
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. */
  10. #include "MultiPseudoStack.h"
  11. #include <cassert>
  12. #include <cstdio>
  13. #define INVALID ((int32_t)0xffffffff)
  14. #define MAX ((int32_t)0x7fffffff)
  15. QueueListItem::QueueListItem(void)
  16. :memory(0), size(0)
  17. {
  18. }
  19. LockFreeQueue::LockFreeQueue(qli_t *data_, int n)
  20. :data(data_), elms(n), next_r(0), next_w(0), avail(0)
  21. {
  22. tag = new std::atomic<uint32_t>[n];
  23. for(int i=0; i<n; ++i)
  24. tag[i] = INVALID;
  25. }
  26. LockFreeQueue::~LockFreeQueue(void)
  27. {
  28. delete [] tag;
  29. }
  30. qli_t *LockFreeQueue::read(void) {
  31. retry:
  32. int8_t free_elms = avail.load();
  33. if(free_elms <= 0)
  34. return 0;
  35. int32_t next_tag = next_r.load();
  36. int32_t next_next_tag = (next_tag+1)&MAX;
  37. assert(next_tag != INVALID);
  38. for(int i=0; i<elms; ++i) {
  39. uint32_t elm_tag = tag[i].load();
  40. //attempt to remove tagged element
  41. //if and only if it's next
  42. if(((uint32_t)next_tag) == elm_tag) {
  43. if(!tag[i].compare_exchange_strong(elm_tag, INVALID))
  44. goto retry;
  45. //Ok, now there is no element that can be removed from the list
  46. //Effectively there's mutual exclusion over other readers here
  47. //Set the next element
  48. int sane_read = next_r.compare_exchange_strong(next_tag, next_next_tag);
  49. assert(sane_read && "No double read on a single tag");
  50. //Decrement available elements
  51. int32_t free_elms_next = avail.load();
  52. while(!avail.compare_exchange_strong(free_elms_next, free_elms_next-1));
  53. //printf("r%d ", free_elms_next-1);
  54. return &data[i];
  55. }
  56. }
  57. goto retry;
  58. }
  59. //Insert Node Q
  60. void LockFreeQueue::write(qli_t *Q) {
  61. retry:
  62. if(!Q)
  63. return;
  64. int32_t write_tag = next_w.load();
  65. int32_t next_write_tag = (write_tag+1)&MAX;
  66. if(!next_w.compare_exchange_strong(write_tag, next_write_tag))
  67. goto retry;
  68. uint32_t invalid_tag = INVALID;
  69. //Update tag
  70. int sane_write = tag[Q-data].compare_exchange_strong(invalid_tag, write_tag);
  71. assert(sane_write);
  72. //Increment available elements
  73. int32_t free_elms = avail.load();
  74. while(!avail.compare_exchange_strong(free_elms, free_elms+1))
  75. assert(free_elms <= 32);
  76. //printf("w%d ", free_elms+1);
  77. }
  78. MultiQueue::MultiQueue(void)
  79. :pool(new qli_t[32]), m_free(pool, 32), m_msgs(pool, 32)
  80. {
  81. //32 instances of 2kBi memory chunks
  82. for(int i=0; i<32; ++i) {
  83. qli_t &ptr = pool[i];
  84. ptr.size = 2048;
  85. ptr.memory = new char[2048];
  86. free(&ptr);
  87. }
  88. }
  89. MultiQueue::~MultiQueue(void)
  90. {
  91. for(int i=0; i<32; ++i)
  92. delete [] pool[i].memory;
  93. delete [] pool;
  94. }