AsyncLoader.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Resource/AsyncLoader.h>
  6. #include <AnKi/Util/Logger.h>
  7. #include <AnKi/Util/Tracer.h>
  8. namespace anki {
  9. AsyncLoader::AsyncLoader()
  10. : m_thread("anki_asyload")
  11. {
  12. }
  13. AsyncLoader::~AsyncLoader()
  14. {
  15. stop();
  16. if(!m_taskQueue.isEmpty())
  17. {
  18. ANKI_RESOURCE_LOGW("Stoping loading thread while there is work to do");
  19. while(!m_taskQueue.isEmpty())
  20. {
  21. AsyncLoaderTask* task = &m_taskQueue.getFront();
  22. m_taskQueue.popFront();
  23. m_alloc.deleteInstance(task);
  24. }
  25. }
  26. }
  27. void AsyncLoader::init(const HeapAllocator<U8>& alloc)
  28. {
  29. m_alloc = alloc;
  30. m_thread.start(this, threadCallback);
  31. }
  32. void AsyncLoader::stop()
  33. {
  34. {
  35. LockGuard<Mutex> lock(m_mtx);
  36. m_quit = true;
  37. m_condVar.notifyOne();
  38. }
  39. [[maybe_unused]] Error err = m_thread.join();
  40. }
  41. void AsyncLoader::pause()
  42. {
  43. {
  44. LockGuard<Mutex> lock(m_mtx);
  45. m_paused = true;
  46. m_sync = true;
  47. m_condVar.notifyOne();
  48. }
  49. m_barrier.wait();
  50. }
  51. void AsyncLoader::resume()
  52. {
  53. LockGuard<Mutex> lock(m_mtx);
  54. m_paused = false;
  55. m_condVar.notifyOne();
  56. }
  57. Error AsyncLoader::threadCallback(ThreadCallbackInfo& info)
  58. {
  59. AsyncLoader& self = *reinterpret_cast<AsyncLoader*>(info.m_userData);
  60. return self.threadWorker();
  61. }
  62. Error AsyncLoader::threadWorker()
  63. {
  64. Error err = Error::NONE;
  65. while(!err)
  66. {
  67. AsyncLoaderTask* task = nullptr;
  68. Bool quit = false;
  69. Bool sync = false;
  70. {
  71. // Wait for something
  72. LockGuard<Mutex> lock(m_mtx);
  73. while((m_taskQueue.isEmpty() || m_paused) && !m_quit && !m_sync)
  74. {
  75. m_condVar.wait(m_mtx);
  76. }
  77. // Do some work
  78. if(m_quit)
  79. {
  80. quit = true;
  81. }
  82. else if(m_sync)
  83. {
  84. sync = true;
  85. m_sync = false;
  86. }
  87. else
  88. {
  89. task = &m_taskQueue.getFront();
  90. m_taskQueue.popFront();
  91. }
  92. }
  93. if(quit)
  94. {
  95. break;
  96. }
  97. else if(sync)
  98. {
  99. m_barrier.wait();
  100. }
  101. else
  102. {
  103. // Exec the task
  104. ANKI_ASSERT(task);
  105. AsyncLoaderTaskContext ctx;
  106. {
  107. ANKI_TRACE_SCOPED_EVENT(RSRC_ASYNC_TASK);
  108. err = (*task)(ctx);
  109. }
  110. if(!err)
  111. {
  112. m_completedTaskCount.fetchAdd(1);
  113. }
  114. else
  115. {
  116. ANKI_RESOURCE_LOGE("Async loader task failed");
  117. }
  118. // Do other stuff
  119. if(ctx.m_resubmitTask)
  120. {
  121. LockGuard<Mutex> lock(m_mtx);
  122. m_taskQueue.pushBack(task);
  123. }
  124. else
  125. {
  126. // Delete the task
  127. m_alloc.deleteInstance(task);
  128. }
  129. if(ctx.m_pause)
  130. {
  131. LockGuard<Mutex> lock(m_mtx);
  132. m_paused = true;
  133. }
  134. }
  135. }
  136. return err;
  137. }
  138. void AsyncLoader::submitTask(AsyncLoaderTask* task)
  139. {
  140. ANKI_ASSERT(task);
  141. // Append task to the list
  142. LockGuard<Mutex> lock(m_mtx);
  143. m_taskQueue.pushBack(task);
  144. if(!m_paused)
  145. {
  146. // Wake up the thread if it's not paused
  147. m_condVar.notifyOne();
  148. }
  149. }
  150. } // end namespace anki