AsyncLoader.cpp 2.8 KB

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